Loading services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java +53 −26 Original line number Diff line number Diff line Loading @@ -20,10 +20,7 @@ import static com.android.internal.util.CollectionUtils.filter; import static com.android.internal.util.FunctionalUtils.uncheckExceptions; import static com.android.server.companion.CompanionDeviceManagerService.DEBUG; import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG; import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId; import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr; import static com.android.server.companion.PermissionsUtils.enforceRequestDeviceProfilePermissions; import static com.android.server.companion.PermissionsUtils.enforceRequestSelfManagedPermission; import static com.android.server.companion.PermissionsUtils.enforceCallerPermissionsToRequest; import static com.android.server.companion.RolesUtils.isRoleHolder; import static java.util.Objects.requireNonNull; Loading Loading @@ -81,7 +78,7 @@ class AssociationRequestsProcessor { mService = service; final Intent serviceIntent = new Intent().setComponent(SERVICE_TO_BIND_TO); mServiceConnectors = new PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>>() { mServiceConnectors = new PerUser<>() { @Override protected ServiceConnector<ICompanionDeviceDiscoveryService> create(int userId) { return new ServiceConnector.Impl<>( Loading @@ -99,6 +96,10 @@ class AssociationRequestsProcessor { void process(@NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId, @NonNull IAssociationRequestCallback callback) { requireNonNull(request, "Request MUST NOT be null"); if (request.isSelfManaged()) { requireNonNull(request.getDisplayName(), "AssociationRequest.displayName " + "MUST NOT be null."); } requireNonNull(packageName, "Package name MUST NOT be null"); requireNonNull(callback, "Callback MUST NOT be null"); Loading @@ -108,33 +109,33 @@ class AssociationRequestsProcessor { + "package=u" + userId + "/" + packageName); } enforceCallerCanInteractWithUserId(mContext, userId); enforceCallerIsSystemOr(userId, packageName); // 1. Enforce permissions and other requirements. enforceCallerPermissionsToRequest(mContext, request, packageName, userId); mService.checkUsesFeature(packageName, userId); if (request.isSelfManaged()) { enforceRequestSelfManagedPermission(mContext); // 2. Check if association can be created without launching UI (i.e. CDM needs NEITHER // to perform discovery NOR to collect user consent). if (request.isSelfManaged() && !request.isForceConfirmation() && !willAddRoleHolder(request, packageName, userId)) { // 2a. Create association right away. final AssociationInfo association = mService.createAssociation(userId, packageName, /* macAddress */ null, request.getDisplayName(), request.getDeviceProfile(), /* selfManaged */true); withCatchingRemoteException(() -> callback.onAssociationCreated(association)); return; } final String deviceProfile = request.getDeviceProfile(); enforceRequestDeviceProfilePermissions(mContext, deviceProfile); // 2b. Launch the UI. synchronized (mService.mLock) { if (mRequest != null) { Slog.w(TAG, "CDM is already processing another AssociationRequest."); try { callback.onFailure("Busy."); } catch (RemoteException e) { // OK to ignore. } return; withCatchingRemoteException(() -> callback.onFailure("Busy.")); } try { callback.asBinder().linkToDeath(mBinderDeathRecipient /* recipient */, 0); } catch (RemoteException e) { final boolean linked = withCatchingRemoteException( () -> callback.asBinder().linkToDeath(mBinderDeathRecipient, 0)); if (!linked) { // The process has died by now: do not proceed. return; } Loading @@ -150,6 +151,7 @@ class AssociationRequestsProcessor { request.setSkipPrompt(true); } final String deviceProfile = request.getDeviceProfile(); mOngoingDeviceDiscovery = getDeviceProfilePermissionDescription(deviceProfile) .thenComposeAsync(description -> { if (DEBUG) { Loading @@ -171,7 +173,7 @@ class AssociationRequestsProcessor { }, FgThread.getExecutor()).whenComplete(uncheckExceptions((deviceAddress, err) -> { if (err == null) { mService.createAssociationInternal( mService.legacyCreateAssociation( userId, deviceAddress, packageName, deviceProfile); mServiceConnectors.forUser(userId).post( ICompanionDeviceDiscoveryService::onAssociationCreated); Loading @@ -183,6 +185,18 @@ class AssociationRequestsProcessor { })); } private boolean willAddRoleHolder(@NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId) { final String deviceProfile = request.getDeviceProfile(); if (deviceProfile == null) return false; final boolean isRoleHolder = Binder.withCleanCallingIdentity( () -> isRoleHolder(mContext, userId, packageName, deviceProfile)); // Don't need to "grant" the role, if the package already holds the role. return !isRoleHolder; } private void cleanup() { if (DEBUG) { Slog.d(TAG, "cleanup(); discovery = " Loading Loading @@ -315,4 +329,17 @@ class AssociationRequestsProcessor { return sameOemPackageCerts; } private static boolean withCatchingRemoteException(ThrowingRunnable runnable) { try { runnable.run(); } catch (RemoteException e) { return false; } return true; } private interface ThrowingRunnable { void run() throws RemoteException; } } services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +24 −16 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ import static com.android.internal.util.Preconditions.checkState; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable; import static com.android.server.companion.PermissionsUtils.checkCallerCanManageAssociationsForPackage; import static com.android.server.companion.PermissionsUtils.checkCallerCanManagerCompanionDevice; import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice; import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId; import static com.android.server.companion.PermissionsUtils.enforceCallerCanManagerCompanionDevice; import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr; Loading Loading @@ -411,7 +411,7 @@ public class CompanionDeviceManagerService extends SystemService { + "permissions to get associations for u" + userId + "/" + packageName); } if (!checkCallerCanManagerCompanionDevice(getContext())) { if (!checkCallerCanManageCompanionDevice(getContext())) { // If the caller neither is system nor holds MANAGE_COMPANION_DEVICES: it needs to // request the feature (also: the caller is the app itself). checkUsesFeature(packageName, getCallingUserId()); Loading Loading @@ -456,7 +456,7 @@ public class CompanionDeviceManagerService extends SystemService { if (association == null) { throw new IllegalArgumentException("Association does not exist " + "or the caller does not have permissions to manage it " + "(ie. it belongs ot a different package or a different user)."); + "(ie. it belongs to a different package or a different user)."); } disassociateInternal(userId, association.getId()); Loading Loading @@ -594,7 +594,7 @@ public class CompanionDeviceManagerService extends SystemService { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES, "createAssociation"); createAssociationInternal(userId, macAddress, packageName, null); legacyCreateAssociation(userId, macAddress, packageName, null); } private void checkCanCallNotificationApi(String callingPackage) { Loading Loading @@ -671,21 +671,29 @@ public class CompanionDeviceManagerService extends SystemService { } } void createAssociationInternal( int userId, String deviceMacAddress, String packageName, String deviceProfile) { final AssociationInfo association = new AssociationInfo( getNewAssociationIdForPackage(userId, packageName), userId, packageName, MacAddress.fromString(deviceMacAddress), null, deviceProfile, /* managedByCompanionApp */false, /* notifyOnDeviceNearby */ false , System.currentTimeMillis()); /** * @deprecated use * {@link #createAssociation(int, String, MacAddress, CharSequence, String, boolean)} */ @Deprecated void legacyCreateAssociation(@UserIdInt int userId, @NonNull String deviceMacAddress, @NonNull String packageName, @Nullable String deviceProfile) { final MacAddress macAddress = MacAddress.fromString(deviceMacAddress); createAssociation(userId, packageName, macAddress, null, deviceProfile, false); } AssociationInfo createAssociation(@UserIdInt int userId, @NonNull String packageName, @Nullable MacAddress macAddress, @Nullable CharSequence displayName, @Nullable String deviceProfile, boolean selfManaged) { final int id = getNewAssociationIdForPackage(userId, packageName); final long timestamp = System.currentTimeMillis(); final AssociationInfo association = new AssociationInfo(id, userId, packageName, macAddress, displayName, deviceProfile, selfManaged, false, timestamp); updateSpecialAccessPermissionForAssociatedPackage(association); recordAssociation(association, userId); return association; } @GuardedBy("mLock") Loading services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ class CompanionDeviceShellCommand extends android.os.ShellCommand { int userId = getNextArgInt(); String packageName = getNextArgRequired(); String address = getNextArgRequired(); mService.createAssociationInternal(userId, address, packageName, null); mService.legacyCreateAssociation(userId, address, packageName, null); } break; Loading services/companion/java/com/android/server/companion/PermissionsUtils.java +16 −2 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.companion.AssociationRequest; import android.companion.CompanionDeviceManager; import android.content.Context; import android.os.RemoteException; Loading Loading @@ -64,6 +65,19 @@ final class PermissionsUtils { DEVICE_PROFILE_TO_PERMISSION = unmodifiableMap(map); } static void enforceCallerPermissionsToRequest(@NonNull Context context, @NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId) { enforceCallerCanInteractWithUserId(context, userId); enforceCallerIsSystemOr(userId, packageName); enforceRequestDeviceProfilePermissions(context, request.getDeviceProfile()); if (request.isSelfManaged()) { enforceRequestSelfManagedPermission(context); } } static void enforceRequestDeviceProfilePermissions( @NonNull Context context, @Nullable String deviceProfile) { // Device profile can be null. Loading Loading @@ -139,7 +153,7 @@ final class PermissionsUtils { } } static boolean checkCallerCanManagerCompanionDevice(@NonNull Context context) { static boolean checkCallerCanManageCompanionDevice(@NonNull Context context) { if (getCallingUserId() == SYSTEM_UID) return true; return context.checkCallingPermission(MANAGE_COMPANION_DEVICES) == PERMISSION_GRANTED; Loading @@ -158,7 +172,7 @@ final class PermissionsUtils { if (!checkCallerCanInteractWithUserId(context, userId)) return false; return checkCallerCanManagerCompanionDevice(context); return checkCallerCanManageCompanionDevice(context); } private static boolean checkPackage(@UserIdInt int uid, @NonNull String packageName) { Loading Loading
services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java +53 −26 Original line number Diff line number Diff line Loading @@ -20,10 +20,7 @@ import static com.android.internal.util.CollectionUtils.filter; import static com.android.internal.util.FunctionalUtils.uncheckExceptions; import static com.android.server.companion.CompanionDeviceManagerService.DEBUG; import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG; import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId; import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr; import static com.android.server.companion.PermissionsUtils.enforceRequestDeviceProfilePermissions; import static com.android.server.companion.PermissionsUtils.enforceRequestSelfManagedPermission; import static com.android.server.companion.PermissionsUtils.enforceCallerPermissionsToRequest; import static com.android.server.companion.RolesUtils.isRoleHolder; import static java.util.Objects.requireNonNull; Loading Loading @@ -81,7 +78,7 @@ class AssociationRequestsProcessor { mService = service; final Intent serviceIntent = new Intent().setComponent(SERVICE_TO_BIND_TO); mServiceConnectors = new PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>>() { mServiceConnectors = new PerUser<>() { @Override protected ServiceConnector<ICompanionDeviceDiscoveryService> create(int userId) { return new ServiceConnector.Impl<>( Loading @@ -99,6 +96,10 @@ class AssociationRequestsProcessor { void process(@NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId, @NonNull IAssociationRequestCallback callback) { requireNonNull(request, "Request MUST NOT be null"); if (request.isSelfManaged()) { requireNonNull(request.getDisplayName(), "AssociationRequest.displayName " + "MUST NOT be null."); } requireNonNull(packageName, "Package name MUST NOT be null"); requireNonNull(callback, "Callback MUST NOT be null"); Loading @@ -108,33 +109,33 @@ class AssociationRequestsProcessor { + "package=u" + userId + "/" + packageName); } enforceCallerCanInteractWithUserId(mContext, userId); enforceCallerIsSystemOr(userId, packageName); // 1. Enforce permissions and other requirements. enforceCallerPermissionsToRequest(mContext, request, packageName, userId); mService.checkUsesFeature(packageName, userId); if (request.isSelfManaged()) { enforceRequestSelfManagedPermission(mContext); // 2. Check if association can be created without launching UI (i.e. CDM needs NEITHER // to perform discovery NOR to collect user consent). if (request.isSelfManaged() && !request.isForceConfirmation() && !willAddRoleHolder(request, packageName, userId)) { // 2a. Create association right away. final AssociationInfo association = mService.createAssociation(userId, packageName, /* macAddress */ null, request.getDisplayName(), request.getDeviceProfile(), /* selfManaged */true); withCatchingRemoteException(() -> callback.onAssociationCreated(association)); return; } final String deviceProfile = request.getDeviceProfile(); enforceRequestDeviceProfilePermissions(mContext, deviceProfile); // 2b. Launch the UI. synchronized (mService.mLock) { if (mRequest != null) { Slog.w(TAG, "CDM is already processing another AssociationRequest."); try { callback.onFailure("Busy."); } catch (RemoteException e) { // OK to ignore. } return; withCatchingRemoteException(() -> callback.onFailure("Busy.")); } try { callback.asBinder().linkToDeath(mBinderDeathRecipient /* recipient */, 0); } catch (RemoteException e) { final boolean linked = withCatchingRemoteException( () -> callback.asBinder().linkToDeath(mBinderDeathRecipient, 0)); if (!linked) { // The process has died by now: do not proceed. return; } Loading @@ -150,6 +151,7 @@ class AssociationRequestsProcessor { request.setSkipPrompt(true); } final String deviceProfile = request.getDeviceProfile(); mOngoingDeviceDiscovery = getDeviceProfilePermissionDescription(deviceProfile) .thenComposeAsync(description -> { if (DEBUG) { Loading @@ -171,7 +173,7 @@ class AssociationRequestsProcessor { }, FgThread.getExecutor()).whenComplete(uncheckExceptions((deviceAddress, err) -> { if (err == null) { mService.createAssociationInternal( mService.legacyCreateAssociation( userId, deviceAddress, packageName, deviceProfile); mServiceConnectors.forUser(userId).post( ICompanionDeviceDiscoveryService::onAssociationCreated); Loading @@ -183,6 +185,18 @@ class AssociationRequestsProcessor { })); } private boolean willAddRoleHolder(@NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId) { final String deviceProfile = request.getDeviceProfile(); if (deviceProfile == null) return false; final boolean isRoleHolder = Binder.withCleanCallingIdentity( () -> isRoleHolder(mContext, userId, packageName, deviceProfile)); // Don't need to "grant" the role, if the package already holds the role. return !isRoleHolder; } private void cleanup() { if (DEBUG) { Slog.d(TAG, "cleanup(); discovery = " Loading Loading @@ -315,4 +329,17 @@ class AssociationRequestsProcessor { return sameOemPackageCerts; } private static boolean withCatchingRemoteException(ThrowingRunnable runnable) { try { runnable.run(); } catch (RemoteException e) { return false; } return true; } private interface ThrowingRunnable { void run() throws RemoteException; } }
services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +24 −16 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ import static com.android.internal.util.Preconditions.checkState; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable; import static com.android.server.companion.PermissionsUtils.checkCallerCanManageAssociationsForPackage; import static com.android.server.companion.PermissionsUtils.checkCallerCanManagerCompanionDevice; import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice; import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId; import static com.android.server.companion.PermissionsUtils.enforceCallerCanManagerCompanionDevice; import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr; Loading Loading @@ -411,7 +411,7 @@ public class CompanionDeviceManagerService extends SystemService { + "permissions to get associations for u" + userId + "/" + packageName); } if (!checkCallerCanManagerCompanionDevice(getContext())) { if (!checkCallerCanManageCompanionDevice(getContext())) { // If the caller neither is system nor holds MANAGE_COMPANION_DEVICES: it needs to // request the feature (also: the caller is the app itself). checkUsesFeature(packageName, getCallingUserId()); Loading Loading @@ -456,7 +456,7 @@ public class CompanionDeviceManagerService extends SystemService { if (association == null) { throw new IllegalArgumentException("Association does not exist " + "or the caller does not have permissions to manage it " + "(ie. it belongs ot a different package or a different user)."); + "(ie. it belongs to a different package or a different user)."); } disassociateInternal(userId, association.getId()); Loading Loading @@ -594,7 +594,7 @@ public class CompanionDeviceManagerService extends SystemService { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES, "createAssociation"); createAssociationInternal(userId, macAddress, packageName, null); legacyCreateAssociation(userId, macAddress, packageName, null); } private void checkCanCallNotificationApi(String callingPackage) { Loading Loading @@ -671,21 +671,29 @@ public class CompanionDeviceManagerService extends SystemService { } } void createAssociationInternal( int userId, String deviceMacAddress, String packageName, String deviceProfile) { final AssociationInfo association = new AssociationInfo( getNewAssociationIdForPackage(userId, packageName), userId, packageName, MacAddress.fromString(deviceMacAddress), null, deviceProfile, /* managedByCompanionApp */false, /* notifyOnDeviceNearby */ false , System.currentTimeMillis()); /** * @deprecated use * {@link #createAssociation(int, String, MacAddress, CharSequence, String, boolean)} */ @Deprecated void legacyCreateAssociation(@UserIdInt int userId, @NonNull String deviceMacAddress, @NonNull String packageName, @Nullable String deviceProfile) { final MacAddress macAddress = MacAddress.fromString(deviceMacAddress); createAssociation(userId, packageName, macAddress, null, deviceProfile, false); } AssociationInfo createAssociation(@UserIdInt int userId, @NonNull String packageName, @Nullable MacAddress macAddress, @Nullable CharSequence displayName, @Nullable String deviceProfile, boolean selfManaged) { final int id = getNewAssociationIdForPackage(userId, packageName); final long timestamp = System.currentTimeMillis(); final AssociationInfo association = new AssociationInfo(id, userId, packageName, macAddress, displayName, deviceProfile, selfManaged, false, timestamp); updateSpecialAccessPermissionForAssociatedPackage(association); recordAssociation(association, userId); return association; } @GuardedBy("mLock") Loading
services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ class CompanionDeviceShellCommand extends android.os.ShellCommand { int userId = getNextArgInt(); String packageName = getNextArgRequired(); String address = getNextArgRequired(); mService.createAssociationInternal(userId, address, packageName, null); mService.legacyCreateAssociation(userId, address, packageName, null); } break; Loading
services/companion/java/com/android/server/companion/PermissionsUtils.java +16 −2 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.companion.AssociationRequest; import android.companion.CompanionDeviceManager; import android.content.Context; import android.os.RemoteException; Loading Loading @@ -64,6 +65,19 @@ final class PermissionsUtils { DEVICE_PROFILE_TO_PERMISSION = unmodifiableMap(map); } static void enforceCallerPermissionsToRequest(@NonNull Context context, @NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId) { enforceCallerCanInteractWithUserId(context, userId); enforceCallerIsSystemOr(userId, packageName); enforceRequestDeviceProfilePermissions(context, request.getDeviceProfile()); if (request.isSelfManaged()) { enforceRequestSelfManagedPermission(context); } } static void enforceRequestDeviceProfilePermissions( @NonNull Context context, @Nullable String deviceProfile) { // Device profile can be null. Loading Loading @@ -139,7 +153,7 @@ final class PermissionsUtils { } } static boolean checkCallerCanManagerCompanionDevice(@NonNull Context context) { static boolean checkCallerCanManageCompanionDevice(@NonNull Context context) { if (getCallingUserId() == SYSTEM_UID) return true; return context.checkCallingPermission(MANAGE_COMPANION_DEVICES) == PERMISSION_GRANTED; Loading @@ -158,7 +172,7 @@ final class PermissionsUtils { if (!checkCallerCanInteractWithUserId(context, userId)) return false; return checkCallerCanManagerCompanionDevice(context); return checkCallerCanManageCompanionDevice(context); } private static boolean checkPackage(@UserIdInt int uid, @NonNull String packageName) { Loading