diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java index 56715b4220693..a7e1a5954aea3 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java @@ -363,13 +363,6 @@ public class CompanionDeviceActivity extends FragmentActivity implements mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data); } - private void onAssociationCreated(@NonNull AssociationInfo association) { - if (DEBUG) Log.i(TAG, "onAssociationCreated(), association=" + association); - - // Don't need to notify the app, CdmService has already done that. Just finish. - setResultAndFinish(association, RESULT_OK); - } - private void cancel(boolean discoveryTimeout, boolean userRejected) { if (DEBUG) { Log.i(TAG, "cancel(), discoveryTimeout=" @@ -413,7 +406,9 @@ public class CompanionDeviceActivity extends FragmentActivity implements } private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) { - if (DEBUG) Log.i(TAG, "setResultAndFinish(), association=" + association); + Log.i(TAG, "setResultAndFinish(), association=" + + (association == null ? "null" : association) + + "resultCode=" + resultCode); final Intent data = new Intent(); if (association != null) { @@ -652,14 +647,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements new ResultReceiver(Handler.getMain()) { @Override protected void onReceiveResult(int resultCode, Bundle data) { - if (resultCode != RESULT_CODE_ASSOCIATION_CREATED) { - throw new RuntimeException("Unknown result code: " + resultCode); + if (resultCode == RESULT_CODE_ASSOCIATION_CREATED) { + final AssociationInfo association = data.getParcelable( + EXTRA_ASSOCIATION, AssociationInfo.class); + requireNonNull(association); + setResultAndFinish(association, RESULT_OK); + } else { + setResultAndFinish(null, resultCode); } - - final AssociationInfo association = data.getParcelable(EXTRA_ASSOCIATION); - requireNonNull(association); - - onAssociationCreated(association); } }; diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java index 80d9d972ed0af..a614b723e11cf 100644 --- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java +++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java @@ -23,8 +23,10 @@ import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVER import static android.content.ComponentName.createRelative; import static com.android.server.companion.CompanionDeviceManagerService.DEBUG; +import static com.android.server.companion.MetricUtils.logCreateAssociation; import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature; import static com.android.server.companion.PermissionsUtils.enforcePermissionsForAssociation; +import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation; import static com.android.server.companion.RolesUtils.isRoleHolder; import static com.android.server.companion.Utils.prepareForIpc; @@ -35,8 +37,10 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UserIdInt; import android.app.PendingIntent; +import android.companion.AssociatedDevice; import android.companion.AssociationInfo; import android.companion.AssociationRequest; +import android.companion.CompanionDeviceManager; import android.companion.IAssociationRequestCallback; import android.content.ComponentName; import android.content.Context; @@ -87,7 +91,7 @@ import java.util.Set; * required. * * If the user's approval is NOT required: an {@link AssociationRequestsProcessor} invokes - * {@link #createAssociationAndNotifyApplication(AssociationRequest, String, int, MacAddress, IAssociationRequestCallback)} + * {@link #createAssociationAndNotifyApplication(AssociationRequest, String, int, MacAddress, IAssociationRequestCallback, ResultReceiver)} * which after calling to {@link CompanionDeviceManagerService} to create an association, notifies * the requester via * {@link android.companion.CompanionDeviceManager.Callback#onAssociationCreated(AssociationInfo)}. @@ -99,7 +103,7 @@ import java.util.Set; * from the Approval UI in via {@link #mOnRequestConfirmationReceiver} and invokes * {@link #processAssociationRequestApproval(AssociationRequest, IAssociationRequestCallback, ResultReceiver, MacAddress)} * which one more time checks that the packages holds all necessary permissions before proceeding to - * {@link #createAssociationAndNotifyApplication(AssociationRequest, String, int, MacAddress, IAssociationRequestCallback)}. + * {@link #createAssociationAndNotifyApplication(AssociationRequest, String, int, MacAddress, IAssociationRequestCallback, ResultReceiver)}. * * @see #processNewAssociationRequest(AssociationRequest, String, int, IAssociationRequestCallback) * @see #processAssociationRequestApproval(AssociationRequest, IAssociationRequestCallback, @@ -132,10 +136,10 @@ class AssociationRequestsProcessor { private final @NonNull Context mContext; private final @NonNull CompanionDeviceManagerService mService; private final @NonNull PackageManagerInternal mPackageManager; - private final @NonNull AssociationStore mAssociationStore; + private final @NonNull AssociationStoreImpl mAssociationStore; AssociationRequestsProcessor(@NonNull CompanionDeviceManagerService service, - @NonNull AssociationStore associationStore) { + @NonNull AssociationStoreImpl associationStore) { mContext = service.getContext(); mService = service; mPackageManager = service.mPackageManagerInternal; @@ -174,7 +178,7 @@ class AssociationRequestsProcessor { && !willAddRoleHolder(request, packageName, userId)) { // 2a. Create association right away. createAssociationAndNotifyApplication(request, packageName, userId, - /*macAddress*/ null, callback); + /* macAddress */ null, callback, /* resultReceiver */ null); return; } @@ -253,34 +257,110 @@ class AssociationRequestsProcessor { } // 2. Create association and notify the application. - final AssociationInfo association = createAssociationAndNotifyApplication( - request, packageName, userId, macAddress, callback); - - // 3. Send the association back the Approval Activity, so that it can report back to the app - // via Activity.setResult(). - final Bundle data = new Bundle(); - data.putParcelable(EXTRA_ASSOCIATION, association); - resultReceiver.send(RESULT_CODE_ASSOCIATION_CREATED, data); + createAssociationAndNotifyApplication(request, packageName, userId, macAddress, callback, + resultReceiver); } - private AssociationInfo createAssociationAndNotifyApplication( + private void createAssociationAndNotifyApplication( @NonNull AssociationRequest request, @NonNull String packageName, @UserIdInt int userId, - @Nullable MacAddress macAddress, @NonNull IAssociationRequestCallback callback) { - final AssociationInfo association; + @Nullable MacAddress macAddress, @NonNull IAssociationRequestCallback callback, + @NonNull ResultReceiver resultReceiver) { final long callingIdentity = Binder.clearCallingIdentity(); try { - association = mService.createAssociation(userId, packageName, macAddress, + createAssociation(userId, packageName, macAddress, request.getDisplayName(), request.getDeviceProfile(), - request.getAssociatedDevice(), request.isSelfManaged()); + request.getAssociatedDevice(), request.isSelfManaged(), + callback, resultReceiver); } finally { Binder.restoreCallingIdentity(callingIdentity); } + } - try { - callback.onAssociationCreated(association); - } catch (RemoteException ignore) { } + public void createAssociation(@UserIdInt int userId, @NonNull String packageName, + @Nullable MacAddress macAddress, @Nullable CharSequence displayName, + @Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice, + boolean selfManaged, @Nullable IAssociationRequestCallback callback, + @Nullable ResultReceiver resultReceiver) { + final int id = mService.getNewAssociationIdForPackage(userId, packageName); + final long timestamp = System.currentTimeMillis(); - return association; + final AssociationInfo association = new AssociationInfo(id, userId, packageName, + macAddress, displayName, deviceProfile, associatedDevice, selfManaged, + /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE); + + if (deviceProfile != null) { + // If the "Device Profile" is specified, make the companion application a holder of the + // corresponding role. + addRoleHolderForAssociation(mService.getContext(), association, success -> { + if (success) { + addAssociationToStore(association, deviceProfile); + + sendCallbackAndFinish(association, callback, resultReceiver); + } else { + Slog.e(TAG, "Failed to add u" + userId + "\\" + packageName + + " to the list of " + deviceProfile + " holders."); + + sendCallbackAndFinish(null, callback, resultReceiver); + } + }); + } else { + addAssociationToStore(association, null); + + sendCallbackAndFinish(association, callback, resultReceiver); + } + + // Don't need to update the mRevokedAssociationsPendingRoleHolderRemoval since + // maybeRemoveRoleHolderForAssociation in PackageInactivityListener will handle the case + // that there are other devices with the same profile, so the role holder won't be removed. + } + + private void addAssociationToStore(@NonNull AssociationInfo association, + @Nullable String deviceProfile) { + Slog.i(TAG, "New CDM association created=" + association); + + mAssociationStore.addAssociation(association); + + mService.updateSpecialAccessPermissionForAssociatedPackage(association); + + logCreateAssociation(deviceProfile); + } + + private void sendCallbackAndFinish(@Nullable AssociationInfo association, + @Nullable IAssociationRequestCallback callback, + @Nullable ResultReceiver resultReceiver) { + if (association != null) { + // Send the association back via the app's callback + if (callback != null) { + try { + callback.onAssociationCreated(association); + } catch (RemoteException ignore) { + } + } + + // Send the association back to CompanionDeviceActivity, so that it can report + // back to the app via Activity.setResult(). + if (resultReceiver != null) { + final Bundle data = new Bundle(); + data.putParcelable(EXTRA_ASSOCIATION, association); + resultReceiver.send(RESULT_CODE_ASSOCIATION_CREATED, data); + } + } else { + // Send the association back via the app's callback + if (callback != null) { + try { + // TODO: update to INTERNAL_ERROR once it's added. + callback.onFailure(CompanionDeviceManager.REASON_CANCELED); + } catch (RemoteException ignore) { + } + } + + // Send the association back to CompanionDeviceActivity, so that it can report + // back to the app via Activity.setResult(). + if (resultReceiver != null) { + final Bundle data = new Bundle(); + resultReceiver.send(CompanionDeviceManager.RESULT_INTERNAL_ERROR, data); + } + } } private boolean willAddRoleHolder(@NonNull AssociationRequest request, diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index f2cb6028e8540..d34fc595ea5e2 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -28,7 +28,6 @@ import static com.android.internal.util.CollectionUtils.any; import static com.android.internal.util.Preconditions.checkState; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED; -import static com.android.server.companion.MetricUtils.logCreateAssociation; import static com.android.server.companion.MetricUtils.logRemoveAssociation; import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature; import static com.android.server.companion.PackageUtils.getPackageInfo; @@ -38,7 +37,6 @@ import static com.android.server.companion.PermissionsUtils.enforceCallerCanMana import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr; import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId; import static com.android.server.companion.PermissionsUtils.sanitizeWithCallerChecks; -import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation; import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation; import static java.util.Objects.requireNonNull; @@ -55,7 +53,6 @@ import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.NotificationManager; import android.app.PendingIntent; -import android.companion.AssociatedDevice; import android.companion.AssociationInfo; import android.companion.AssociationRequest; import android.companion.DeviceNotAssociatedException; @@ -819,7 +816,8 @@ public class CompanionDeviceManagerService extends SystemService { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES, "createAssociation"); - legacyCreateAssociation(userId, macAddress, packageName, null); + final MacAddress macAddressObj = MacAddress.fromString(macAddress); + createNewAssociation(userId, packageName, macAddressObj, null, null, false); } private void checkCanCallNotificationApi(String callingPackage) { @@ -871,45 +869,12 @@ public class CompanionDeviceManagerService extends SystemService { } } - /** - * @deprecated use - * {@link #createAssociation(int, String, MacAddress, CharSequence, String, AssociatedDevice, - * 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, null, false); - } - - AssociationInfo createAssociation(@UserIdInt int userId, @NonNull String packageName, + void createNewAssociation(@UserIdInt int userId, @NonNull String packageName, @Nullable MacAddress macAddress, @Nullable CharSequence displayName, - @Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice, - boolean selfManaged) { - final int id = getNewAssociationIdForPackage(userId, packageName); - final long timestamp = System.currentTimeMillis(); - - final AssociationInfo association = new AssociationInfo(id, userId, packageName, - macAddress, displayName, deviceProfile, associatedDevice, selfManaged, - /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE); - Slog.i(TAG, "New CDM association created=" + association); - mAssociationStore.addAssociation(association); - - // If the "Device Profile" is specified, make the companion application a holder of the - // corresponding role. - if (deviceProfile != null) { - addRoleHolderForAssociation(getContext(), association); - } - - updateSpecialAccessPermissionForAssociatedPackage(association); - logCreateAssociation(deviceProfile); - - // Don't need to update the mRevokedAssociationsPendingRoleHolderRemoval since - // maybeRemoveRoleHolderForAssociation in PackageInactivityListener will handle the case - // that there are other devices with the same profile, so the role holder won't be removed. - - return association; + @Nullable String deviceProfile, boolean isSelfManaged) { + mAssociationRequestsProcessor.createAssociation(userId, packageName, macAddress, + displayName, deviceProfile, /* associatedDevice */ null, isSelfManaged, + /* callback */ null, /* resultReceiver */ null); } @NonNull @@ -946,7 +911,7 @@ public class CompanionDeviceManagerService extends SystemService { return usedIdsForPackage; } - private int getNewAssociationIdForPackage(@UserIdInt int userId, @NonNull String packageName) { + int getNewAssociationIdForPackage(@UserIdInt int userId, @NonNull String packageName) { synchronized (mPreviouslyUsedIds) { // First: collect all IDs currently in use for this user's Associations. final SparseBooleanArray usedIds = new SparseBooleanArray(); @@ -1170,7 +1135,7 @@ public class CompanionDeviceManagerService extends SystemService { } } - private void updateSpecialAccessPermissionForAssociatedPackage(AssociationInfo association) { + void updateSpecialAccessPermissionForAssociatedPackage(AssociationInfo association) { final PackageInfo packageInfo = getPackageInfo(getContext(), association.getUserId(), association.getPackageName()); diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java index d24f9e3df3821..6889bcd633554 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java @@ -17,6 +17,7 @@ package com.android.server.companion; import android.companion.AssociationInfo; +import android.net.MacAddress; import android.os.Binder; import android.os.ShellCommand; @@ -63,7 +64,9 @@ class CompanionDeviceShellCommand extends ShellCommand { int userId = getNextIntArgRequired(); String packageName = getNextArgRequired(); String address = getNextArgRequired(); - mService.legacyCreateAssociation(userId, address, packageName, null); + final MacAddress macAddress = MacAddress.fromString(address); + mService.createNewAssociation(userId, packageName, macAddress, + null, null, false); } break; diff --git a/services/companion/java/com/android/server/companion/RolesUtils.java b/services/companion/java/com/android/server/companion/RolesUtils.java index 0fff3f4885625..f674a7d20b822 100644 --- a/services/companion/java/com/android/server/companion/RolesUtils.java +++ b/services/companion/java/com/android/server/companion/RolesUtils.java @@ -32,6 +32,7 @@ import android.util.Log; import android.util.Slog; import java.util.List; +import java.util.function.Consumer; /** Utility methods for accessing {@link RoleManager} APIs. */ @SuppressLint("LongLogTag") @@ -46,7 +47,8 @@ final class RolesUtils { } static void addRoleHolderForAssociation( - @NonNull Context context, @NonNull AssociationInfo associationInfo) { + @NonNull Context context, @NonNull AssociationInfo associationInfo, + @NonNull Consumer roleGrantResult) { if (DEBUG) { Log.d(TAG, "addRoleHolderForAssociation() associationInfo=" + associationInfo); } @@ -62,12 +64,7 @@ final class RolesUtils { roleManager.addRoleHolderAsUser(deviceProfile, packageName, MANAGE_HOLDERS_FLAG_DONT_KILL_APP, userHandle, context.getMainExecutor(), - success -> { - if (!success) { - Slog.e(TAG, "Failed to add u" + userId + "\\" + packageName - + " to the list of " + deviceProfile + " holders."); - } - }); + roleGrantResult); } static void removeRoleHolderForAssociation(