Merge "Update role grant flow to be synchronized"

This commit is contained in:
Guojing Yuan
2022-10-13 18:49:01 +00:00
committed by Android (Google) Code Review
5 changed files with 129 additions and 89 deletions

View File

@@ -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);
}
};

View File

@@ -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,

View File

@@ -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());

View File

@@ -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;

View File

@@ -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<Boolean> 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(