Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d76a0a2 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Long-tail of AttributionSource plumbing.

Wires up AttributionSource across the remaining long-tail of
Bluetooth AIDL interfaces, ensuring that developers can accurately
make calls chained back to a specific Context.

Moves "for data delivery" permission checks to happen in a single
location on each interface to ensure they're performed consistently
with the new AttributionSource arguments.  Note that "for data
delivery" isn't the best name; it's designed to represent that the
requested action was performed and should result in the relevant
appop being noted for the caller.

This change has the positive side effect of ensuring that all
interfaces are consistently enforcing the BLUETOOTH_CONNECT
permission, even in the case where BLUETOOTH_PRIVILEGED is also
required; this is what ensures that revoking the "Nearby devices"
permission takes effect for all callers.

Additionally, standardizing on enforcing permissions closer to the
AIDL entry point reduces the need for @RequiresPermission annotations
to be carried around inside the Bluetooth stack.

Bug: 183626112
Test: atest BluetoothInstrumentationTests
Change-Id: I389e9938c0f0e6f5fa686182ff913fcfa66d1d4b
parent de3b1db4
Loading
Loading
Loading
Loading
+68 −21
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
@@ -49,12 +50,15 @@ import android.os.Binder;
import android.os.Build;
import android.os.Build;
import android.os.ParcelUuid;
import android.os.ParcelUuid;
import android.os.Process;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.provider.Telephony;
import android.provider.Telephony;
import android.util.Log;
import android.util.Log;


import com.android.bluetooth.btservice.ProfileService;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserException;


@@ -392,6 +396,20 @@ public final class Utils {
                "Need DUMP permission");
                "Need DUMP permission");
    }
    }


    public static AttributionSource getCallingAttributionSource() {
        int callingUid = Binder.getCallingUid();
        if (callingUid == android.os.Process.ROOT_UID) {
            callingUid = android.os.Process.SYSTEM_UID;
        }
        try {
            return new AttributionSource(callingUid,
                    AppGlobals.getPackageManager().getPackagesForUid(callingUid)[0], null);
        } catch (RemoteException e) {
            throw new IllegalStateException("Failed to resolve AttributionSource", e);
        }
    }

    @SuppressLint("AndroidFrameworkRequiresPermission")
    private static boolean checkPermissionForPreflight(Context context, String permission) {
    private static boolean checkPermissionForPreflight(Context context, String permission) {
        final int result = PermissionChecker.checkCallingOrSelfPermissionForPreflight(
        final int result = PermissionChecker.checkCallingOrSelfPermissionForPreflight(
                context, permission);
                context, permission);
@@ -408,6 +426,7 @@ public final class Utils {
        }
        }
    }
    }


    @SuppressLint("AndroidFrameworkRequiresPermission")
    private static boolean checkPermissionForDataDelivery(Context context, String permission,
    private static boolean checkPermissionForDataDelivery(Context context, String permission,
            AttributionSource attributionSource, String message) {
            AttributionSource attributionSource, String message) {
        final int result = PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
        final int result = PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
@@ -434,6 +453,7 @@ public final class Utils {
     *
     *
     * <p>Should be used in situations where the app op should not be noted.
     * <p>Should be used in situations where the app op should not be noted.
     */
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    public static boolean checkConnectPermissionForPreflight(Context context) {
    public static boolean checkConnectPermissionForPreflight(Context context) {
        return checkPermissionForPreflight(context, BLUETOOTH_CONNECT);
        return checkPermissionForPreflight(context, BLUETOOTH_CONNECT);
@@ -447,6 +467,7 @@ public final class Utils {
     * <p>Should be used in situations where data will be delivered and hence the app op should
     * <p>Should be used in situations where data will be delivered and hence the app op should
     * be noted.
     * be noted.
     */
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    public static boolean checkConnectPermissionForDataDelivery(
    public static boolean checkConnectPermissionForDataDelivery(
            Context context, AttributionSource attributionSource, String message) {
            Context context, AttributionSource attributionSource, String message) {
@@ -460,6 +481,7 @@ public final class Utils {
     *
     *
     * <p>Should be used in situations where the app op should not be noted.
     * <p>Should be used in situations where the app op should not be noted.
     */
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
    public static boolean checkScanPermissionForPreflight(Context context) {
    public static boolean checkScanPermissionForPreflight(Context context) {
        return checkPermissionForPreflight(context, BLUETOOTH_SCAN);
        return checkPermissionForPreflight(context, BLUETOOTH_SCAN);
@@ -472,6 +494,7 @@ public final class Utils {
     * <p>Should be used in situations where data will be delivered and hence the app op should
     * <p>Should be used in situations where data will be delivered and hence the app op should
     * be noted.
     * be noted.
     */
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
    public static boolean checkScanPermissionForDataDelivery(
    public static boolean checkScanPermissionForDataDelivery(
            Context context, AttributionSource attributionSource, String message) {
            Context context, AttributionSource attributionSource, String message) {
@@ -486,6 +509,7 @@ public final class Utils {
     * <p>
     * <p>
     * Should be used in situations where the app op should not be noted.
     * Should be used in situations where the app op should not be noted.
     */
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
    public static boolean checkAdvertisePermissionForPreflight(Context context) {
    public static boolean checkAdvertisePermissionForPreflight(Context context) {
        return checkPermissionForPreflight(context, BLUETOOTH_ADVERTISE);
        return checkPermissionForPreflight(context, BLUETOOTH_ADVERTISE);
@@ -499,6 +523,7 @@ public final class Utils {
     * Should be used in situations where data will be delivered and hence the
     * Should be used in situations where data will be delivered and hence the
     * app op should be noted.
     * app op should be noted.
     */
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
    public static boolean checkAdvertisePermissionForDataDelivery(
    public static boolean checkAdvertisePermissionForDataDelivery(
            Context context, AttributionSource attributionSource, String message) {
            Context context, AttributionSource attributionSource, String message) {
@@ -539,23 +564,7 @@ public final class Utils {
        return false;
        return false;
    }
    }


    public static boolean callerIsSystemOrActiveUser(String tag, String method) {
    public static boolean checkCallerIsSystemOrActiveUser() {
        if (!checkCaller()) {
          Log.w(TAG, method + "() - Not allowed for non-active user and non-system user");
          return false;
        }
        return true;
    }

    public static boolean callerIsSystemOrActiveOrManagedUser(Context context, String tag, String method) {
        if (!checkCallerAllowManagedProfiles(context)) {
          Log.w(TAG, method + "() - Not allowed for non-active user and non-system and non-managed user");
          return false;
        }
        return true;
    }

    public static boolean checkCaller() {
        int callingUser = UserHandle.getCallingUserId();
        int callingUser = UserHandle.getCallingUserId();
        int callingUid = Binder.getCallingUid();
        int callingUid = Binder.getCallingUid();
        return (sForegroundUserId == callingUser)
        return (sForegroundUserId == callingUser)
@@ -563,9 +572,21 @@ public final class Utils {
                || (UserHandle.getAppId(Process.SYSTEM_UID) == UserHandle.getAppId(callingUid));
                || (UserHandle.getAppId(Process.SYSTEM_UID) == UserHandle.getAppId(callingUid));
    }
    }


    public static boolean checkCallerAllowManagedProfiles(Context mContext) {
    public static boolean checkCallerIsSystemOrActiveUser(String tag) {
        if (mContext == null) {
        final boolean res = checkCallerIsSystemOrActiveUser();
            return checkCaller();
        if (!res) {
            Log.w(TAG, tag + " - Not allowed for non-active user and non-system user");
        }
        return res;
    }

    public static boolean callerIsSystemOrActiveUser(String tag, String method) {
        return checkCallerIsSystemOrActiveUser(tag + "." + method + "()");
    }

    public static boolean checkCallerIsSystemOrActiveOrManagedUser(Context context) {
        if (context == null) {
            return checkCallerIsSystemOrActiveUser();
        }
        }
        int callingUser = UserHandle.getCallingUserId();
        int callingUser = UserHandle.getCallingUserId();
        int callingUid = Binder.getCallingUid();
        int callingUid = Binder.getCallingUid();
@@ -573,7 +594,7 @@ public final class Utils {
        // Use the Bluetooth process identity when making call to get parent user
        // Use the Bluetooth process identity when making call to get parent user
        long ident = Binder.clearCallingIdentity();
        long ident = Binder.clearCallingIdentity();
        try {
        try {
            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
            UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
            UserInfo ui = um.getProfileParent(callingUser);
            UserInfo ui = um.getProfileParent(callingUser);
            int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
            int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;


@@ -589,6 +610,32 @@ public final class Utils {
        }
        }
    }
    }


    public static boolean checkCallerIsSystemOrActiveOrManagedUser(Context context, String tag) {
        final boolean res = checkCallerIsSystemOrActiveOrManagedUser(context);
        if (!res) {
            Log.w(TAG, tag + " - Not allowed for"
                    + " non-active user and non-system and non-managed user");
        }
        return res;
    }

    public static boolean callerIsSystemOrActiveOrManagedUser(Context context, String tag,
            String method) {
        return checkCallerIsSystemOrActiveOrManagedUser(context, tag + "." + method + "()");
    }

    public static boolean checkServiceAvailable(ProfileService service, String tag) {
        if (service == null) {
            Log.w(TAG, tag + " - Not present");
            return false;
        }
        if (!service.isAvailable()) {
            Log.w(TAG, tag + " - Not available");
            return false;
        }
        return true;
    }

    /**
    /**
     * Checks whether location is off and must be on for us to perform some operation
     * Checks whether location is off and must be on for us to perform some operation
     */
     */
+0 −1
Original line number Original line Diff line number Diff line
@@ -205,7 +205,6 @@ public class A2dpNativeInterface {
        sendMessageToService(event);
        sendMessageToService(event);
    }
    }


    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    private boolean isMandatoryCodecPreferred(byte[] address) {
    private boolean isMandatoryCodecPreferred(byte[] address) {
        A2dpService service = A2dpService.getA2dpService();
        A2dpService service = A2dpService.getA2dpService();
        if (service != null) {
        if (service != null) {
Loading