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

Commit f890cb39 authored by Evan Chen's avatar Evan Chen
Browse files

Additional permission for Device Presence UUID matching.

App must hole Android Auto Projection role in order
to use Device Presence UUID matching.

Also added shell commands to trigger the observing base on the UUID for
CTS.

Flag: android.companion.device_presence
Test: CTS
Bug: b/330793558
Change-Id: Ieb5fe46d94e3fbf669a871d8571c1c2f7354fe24
parent 9cca183f
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -180,6 +180,9 @@ public final class ObservingDevicePresenceRequest implements Parcelable {
         * <p>Calling apps must use either this API or {@link #setAssociationId(int)},
         * <p>Calling apps must use either this API or {@link #setAssociationId(int)},
         * but not both.</p>
         * but not both.</p>
         *
         *
         * <p>Calling app must hold the
         * {@link AssociationRequest#DEVICE_PROFILE_AUTOMOTIVE_PROJECTION} profile.</p>
         *
         * @param uuid The ParcelUuid for observing device presence.
         * @param uuid The ParcelUuid for observing device presence.
         */
         */
        @NonNull
        @NonNull
+4 −2
Original line number Original line Diff line number Diff line
@@ -535,7 +535,8 @@ public class CompanionDeviceManagerService extends SystemService {
                String packageName, int userId) {
                String packageName, int userId) {
            startObservingDevicePresence_enforcePermission();
            startObservingDevicePresence_enforcePermission();


            mDevicePresenceProcessor.startObservingDevicePresence(request, packageName, userId);
            mDevicePresenceProcessor.startObservingDevicePresence(
                    request, packageName, userId, /* enforcePermissions */ true);
        }
        }


        @Override
        @Override
@@ -544,7 +545,8 @@ public class CompanionDeviceManagerService extends SystemService {
                String packageName, int userId) {
                String packageName, int userId) {
            stopObservingDevicePresence_enforcePermission();
            stopObservingDevicePresence_enforcePermission();


            mDevicePresenceProcessor.stopObservingDevicePresence(request, packageName, userId);
            mDevicePresenceProcessor.stopObservingDevicePresence(
                    request, packageName, userId, /* enforcePermissions */ true);
        }
        }


        @Override
        @Override
+46 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_S
import android.companion.AssociationInfo;
import android.companion.AssociationInfo;
import android.companion.ContextSyncMessage;
import android.companion.ContextSyncMessage;
import android.companion.Flags;
import android.companion.Flags;
import android.companion.ObservingDevicePresenceRequest;
import android.companion.Telecom;
import android.companion.Telecom;
import android.companion.datatransfer.PermissionSyncRequest;
import android.companion.datatransfer.PermissionSyncRequest;
import android.net.MacAddress;
import android.net.MacAddress;
@@ -193,6 +194,43 @@ class CompanionDeviceShellCommand extends ShellCommand {
                    break;
                    break;
                }
                }


                case "start-observing-device-presence-uuid": {
                    if (Flags.devicePresence()) {
                        int userId = getNextIntArgRequired();
                        String packageName = getNextArgRequired();
                        String uuid = getNextArgRequired();
                        if ("null".equals(uuid)) {
                            out.println("UUID can not be null.");
                            break;
                        }
                        ParcelUuid parcelUuid = ParcelUuid.fromString(uuid);
                        ObservingDevicePresenceRequest request = new ObservingDevicePresenceRequest
                                .Builder().setUuid(parcelUuid).build();
                        mDevicePresenceProcessor.startObservingDevicePresence(
                                request, packageName, userId, /* enforcePermissions */ false);

                    }
                    break;
                }

                case "stop-observing-device-presence-uuid": {
                    if (Flags.devicePresence()) {
                        int userId = getNextIntArgRequired();
                        String packageName = getNextArgRequired();
                        String uuid = getNextArgRequired();
                        if ("null".equals(uuid)) {
                            out.println("UUID can not be null.");
                            break;
                        }
                        ParcelUuid parcelUuid = ParcelUuid.fromString(uuid);
                        ObservingDevicePresenceRequest request = new ObservingDevicePresenceRequest
                                .Builder().setUuid(parcelUuid).build();
                        mDevicePresenceProcessor.stopObservingDevicePresence(
                                request, packageName, userId, /* enforcePermissions */ false);
                    }
                    break;
                }

                case "get-backup-payload": {
                case "get-backup-payload": {
                    final int userId = getNextIntArgRequired();
                    final int userId = getNextIntArgRequired();
                    byte[] payload = mBackupRestoreProcessor.getBackupPayload(userId);
                    byte[] payload = mBackupRestoreProcessor.getBackupPayload(userId);
@@ -515,6 +553,14 @@ class CompanionDeviceShellCommand extends ShellCommand {
            pw.println("  callback after simulate-device-event-device-locked");
            pw.println("  callback after simulate-device-event-device-locked");
            pw.println("  command has been called.");
            pw.println("  command has been called.");
            pw.println("  USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
            pw.println("  USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");

            pw.println("  start-observing-device-presence-uuid USER_ID PACKAGE_NAME UUID");
            pw.println("  Start observing device presence base on the UUID.");
            pw.println("  USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");

            pw.println("  stop-observing-device-presence-uuid USER_ID PACKAGE_NAME UUID");
            pw.println("  Stop observing device presence base on the UUID.");
            pw.println("  USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
        }
        }


        pw.println("  remove-inactive-associations");
        pw.println("  remove-inactive-associations");
+12 −8
Original line number Original line Diff line number Diff line
@@ -181,14 +181,16 @@ public class DevicePresenceProcessor implements AssociationStore.OnChangeListene
     * Process device presence start request.
     * Process device presence start request.
     */
     */
    public void startObservingDevicePresence(ObservingDevicePresenceRequest request,
    public void startObservingDevicePresence(ObservingDevicePresenceRequest request,
            String packageName, int userId) {
            String packageName, int userId, boolean enforcePermissions) {
        Slog.i(TAG,
        Slog.i(TAG,
                "Start observing request=[" + request + "] for userId=[" + userId + "], package=["
                "Start observing request=[" + request + "] for userId=[" + userId + "], package=["
                        + packageName + "]...");
                        + packageName + "]...");
        final ParcelUuid requestUuid = request.getUuid();
        final ParcelUuid requestUuid = request.getUuid();


        if (requestUuid != null) {
        if (requestUuid != null) {
            enforceCallerCanObserveDevicePresenceByUuid(mContext);
            if (enforcePermissions) {
                enforceCallerCanObserveDevicePresenceByUuid(mContext, packageName, userId);
            }


            // If it's already being observed, then no-op.
            // If it's already being observed, then no-op.
            if (mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
            if (mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
@@ -236,7 +238,7 @@ public class DevicePresenceProcessor implements AssociationStore.OnChangeListene
     * Process device presence stop request.
     * Process device presence stop request.
     */
     */
    public void stopObservingDevicePresence(ObservingDevicePresenceRequest request,
    public void stopObservingDevicePresence(ObservingDevicePresenceRequest request,
            String packageName, int userId) {
            String packageName, int userId, boolean enforcePermissions) {
        Slog.i(TAG,
        Slog.i(TAG,
                "Stop observing request=[" + request + "] for userId=[" + userId + "], package=["
                "Stop observing request=[" + request + "] for userId=[" + userId + "], package=["
                        + packageName + "]...");
                        + packageName + "]...");
@@ -244,7 +246,9 @@ public class DevicePresenceProcessor implements AssociationStore.OnChangeListene
        final ParcelUuid requestUuid = request.getUuid();
        final ParcelUuid requestUuid = request.getUuid();


        if (requestUuid != null) {
        if (requestUuid != null) {
            enforceCallerCanObserveDevicePresenceByUuid(mContext);
            if (enforcePermissions) {
                enforceCallerCanObserveDevicePresenceByUuid(mContext, packageName, userId);
            }


            if (!mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
            if (!mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
                Slog.i(TAG, "UUID=[" + requestUuid + "], package=[" + packageName + "], userId=["
                Slog.i(TAG, "UUID=[" + requestUuid + "], package=[" + packageName + "], userId=["
@@ -283,7 +287,7 @@ public class DevicePresenceProcessor implements AssociationStore.OnChangeListene
     * For legacy device presence below Android V.
     * For legacy device presence below Android V.
     *
     *
     * @deprecated Use {@link #startObservingDevicePresence(ObservingDevicePresenceRequest, String,
     * @deprecated Use {@link #startObservingDevicePresence(ObservingDevicePresenceRequest, String,
     * int)}
     * int, boolean)}
     */
     */
    @Deprecated
    @Deprecated
    public void startObservingDevicePresence(int userId, String packageName, String deviceAddress)
    public void startObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -306,14 +310,14 @@ public class DevicePresenceProcessor implements AssociationStore.OnChangeListene


        startObservingDevicePresence(
        startObservingDevicePresence(
                new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
                new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
                        .build(), packageName, userId);
                        .build(), packageName, userId, /* enforcePermissions */ true);
    }
    }


    /**
    /**
     * For legacy device presence below Android V.
     * For legacy device presence below Android V.
     *
     *
     * @deprecated Use {@link #stopObservingDevicePresence(ObservingDevicePresenceRequest, String,
     * @deprecated Use {@link #stopObservingDevicePresence(ObservingDevicePresenceRequest, String,
     * int)}
     * int, boolean)}
     */
     */
    @Deprecated
    @Deprecated
    public void stopObservingDevicePresence(int userId, String packageName, String deviceAddress)
    public void stopObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -336,7 +340,7 @@ public class DevicePresenceProcessor implements AssociationStore.OnChangeListene


        stopObservingDevicePresence(
        stopObservingDevicePresence(
                new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
                new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
                        .build(), packageName, userId);
                        .build(), packageName, userId, /* enforcePermissions */ true);
    }
    }


    /**
    /**
+17 −5
Original line number Original line Diff line number Diff line
@@ -35,6 +35,8 @@ import static android.os.Binder.getCallingUid;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.getCallingUserId;
import static android.os.UserHandle.getCallingUserId;


import static com.android.server.companion.utils.RolesUtils.isRoleHolder;

import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableMap;


import android.Manifest;
import android.Manifest;
@@ -44,6 +46,7 @@ import android.annotation.UserIdInt;
import android.companion.AssociationRequest;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
import android.companion.CompanionDeviceManager;
import android.content.Context;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.ArrayMap;
@@ -209,11 +212,9 @@ public final class PermissionsUtils {
    /**
    /**
     * Require the caller to hold necessary permission to observe device presence by UUID.
     * Require the caller to hold necessary permission to observe device presence by UUID.
     */
     */
    public static void enforceCallerCanObserveDevicePresenceByUuid(@NonNull Context context) {
    public static void enforceCallerCanObserveDevicePresenceByUuid(@NonNull Context context,
        if (context.checkCallingPermission(REQUEST_OBSERVE_DEVICE_UUID_PRESENCE)
            String packageName, int userId) {
                != PERMISSION_GRANTED
        if (!hasRequirePermissions(context, packageName, userId)) {
                || context.checkCallingPermission(BLUETOOTH_SCAN) != PERMISSION_GRANTED
                || context.checkCallingPermission(BLUETOOTH_CONNECT) != PERMISSION_GRANTED) {
            throw new SecurityException("Caller (uid=" + getCallingUid() + ") does not have "
            throw new SecurityException("Caller (uid=" + getCallingUid() + ") does not have "
                    + "permissions to request observing device presence base on the UUID");
                    + "permissions to request observing device presence base on the UUID");
        }
        }
@@ -259,6 +260,17 @@ public final class PermissionsUtils {
        return sAppOpsService;
        return sAppOpsService;
    }
    }


    private static boolean hasRequirePermissions(
            @NonNull Context context, String packageName, int userId) {
        return context.checkCallingPermission(
                REQUEST_OBSERVE_DEVICE_UUID_PRESENCE) == PERMISSION_GRANTED
                && context.checkCallingPermission(BLUETOOTH_SCAN) == PERMISSION_GRANTED
                && context.checkCallingPermission(BLUETOOTH_CONNECT) == PERMISSION_GRANTED
                && Boolean.TRUE.equals(Binder.withCleanCallingIdentity(
                        () -> isRoleHolder(context, userId, packageName,
                                DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)));
    }

    // DO NOT USE DIRECTLY! Access via getAppOpsService().
    // DO NOT USE DIRECTLY! Access via getAppOpsService().
    private static IAppOpsService sAppOpsService = null;
    private static IAppOpsService sAppOpsService = null;