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

Commit 438d2633 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 d30fee51
Loading
Loading
Loading
Loading
+68 −21
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -49,12 +50,15 @@ import android.os.Binder;
import android.os.Build;
import android.os.ParcelUuid;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Telephony;
import android.util.Log;

import com.android.bluetooth.btservice.ProfileService;

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

@@ -392,6 +396,20 @@ public final class Utils {
                "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) {
        final int result = PermissionChecker.checkCallingOrSelfPermissionForPreflight(
                context, permission);
@@ -408,6 +426,7 @@ public final class Utils {
        }
    }

    @SuppressLint("AndroidFrameworkRequiresPermission")
    private static boolean checkPermissionForDataDelivery(Context context, String permission,
            AttributionSource attributionSource, String message) {
        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.
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    public static boolean checkConnectPermissionForPreflight(Context context) {
        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
     * be noted.
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    public static boolean checkConnectPermissionForDataDelivery(
            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.
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
    public static boolean checkScanPermissionForPreflight(Context context) {
        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
     * be noted.
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
    public static boolean checkScanPermissionForDataDelivery(
            Context context, AttributionSource attributionSource, String message) {
@@ -486,6 +509,7 @@ public final class Utils {
     * <p>
     * Should be used in situations where the app op should not be noted.
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
    public static boolean checkAdvertisePermissionForPreflight(Context context) {
        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
     * app op should be noted.
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
    public static boolean checkAdvertisePermissionForDataDelivery(
            Context context, AttributionSource attributionSource, String message) {
@@ -539,23 +564,7 @@ public final class Utils {
        return false;
    }

    public static boolean callerIsSystemOrActiveUser(String tag, String method) {
        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() {
    public static boolean checkCallerIsSystemOrActiveUser() {
        int callingUser = UserHandle.getCallingUserId();
        int callingUid = Binder.getCallingUid();
        return (sForegroundUserId == callingUser)
@@ -563,9 +572,21 @@ public final class Utils {
                || (UserHandle.getAppId(Process.SYSTEM_UID) == UserHandle.getAppId(callingUid));
    }

    public static boolean checkCallerAllowManagedProfiles(Context mContext) {
        if (mContext == null) {
            return checkCaller();
    public static boolean checkCallerIsSystemOrActiveUser(String tag) {
        final boolean res = checkCallerIsSystemOrActiveUser();
        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 callingUid = Binder.getCallingUid();
@@ -573,7 +594,7 @@ public final class Utils {
        // Use the Bluetooth process identity when making call to get parent user
        long ident = Binder.clearCallingIdentity();
        try {
            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
            UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
            UserInfo ui = um.getProfileParent(callingUser);
            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
     */
+0 −1
Original line number Diff line number Diff line
@@ -205,7 +205,6 @@ public class A2dpNativeInterface {
        sendMessageToService(event);
    }

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