diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index b052bc53ddbfd..a9ec11edd6808 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -178,17 +178,16 @@ interface IActivityTaskManager { Point getAppTaskThumbnailSize(); /** * Only callable from the system. This token grants a temporary permission to call - * #startActivityAsCallerWithToken. The token will time out after - * START_AS_CALLER_TOKEN_TIMEOUT if it is not used. + * #startActivityAsCaller. The token will time out after START_AS_CALLER_TOKEN_TIMEOUT + * if it is not used. * - * @param delegatorToken The Binder token referencing the system Activity that wants to delegate - * the #startActivityAsCaller to another app. The "caller" will be the caller of this - * activity's token, not the delegate's caller (which is probably the delegator itself). + * @param componentName The component name of the delegated component that is allowed to + * call #startActivityAsCaller with the returned token. * * @return Returns a token that can be given to a "delegate" app that may call * #startActivityAsCaller */ - IBinder requestStartActivityPermissionToken(in IBinder delegatorToken); + IBinder requestStartActivityPermissionToken(in ComponentName componentName); oneway void releaseSomeActivities(in IApplicationThread app); Bitmap getTaskDescriptionIcon(in String filename, int userId); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index bc3c2f5872fc8..e5f96f5e98406 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -759,11 +759,11 @@ public class ChooserActivity extends ResolverActivity implements } try { - IBinder permissionToken = ActivityTaskManager.getService() - .requestStartActivityPermissionToken(getActivityToken()); Intent delegationIntent = new Intent(); final ComponentName delegateActivity = ComponentName.unflattenFromString( Resources.getSystem().getString(R.string.config_chooserActivity)); + IBinder permissionToken = ActivityTaskManager.getService() + .requestStartActivityPermissionToken(delegateActivity); delegationIntent.setComponent(delegateActivity); delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent()); delegationIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken); diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index b273f6ded8d06..f9a8c7b58897c 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1437,11 +1437,11 @@ public class ResolverActivity extends Activity implements try { // TODO: Once this is a small springboard activity, it can move off the UI process // and we can move the request method to ActivityManagerInternal. - IBinder permissionToken = ActivityTaskManager.getService() - .requestStartActivityPermissionToken(getActivityToken()); final Intent chooserIntent = new Intent(); final ComponentName delegateActivity = ComponentName.unflattenFromString( Resources.getSystem().getString(R.string.config_chooserActivity)); + IBinder permissionToken = ActivityTaskManager.getService() + .requestStartActivityPermissionToken(delegateActivity); chooserIntent.setClassName(delegateActivity.getPackageName(), delegateActivity.getClassName()); chooserIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 15ebe28465134..c7d884282c9a9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -436,9 +436,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private static final long START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT = START_AS_CALLER_TOKEN_TIMEOUT_IMPL + 20 * MINUTE_IN_MILLIS; - // Activity tokens of system activities that are delegating their call to - // #startActivityByCaller, keyed by the permissionToken granted to the delegate. - final HashMap mStartActivitySources = new HashMap<>(); + // The component name of the delegated activities that are allowed to call + // #startActivityAsCaller with the one-time used permission token. + final HashMap mStartActivitySources = new HashMap<>(); // Permission tokens that have expired, but we remember for error reporting. final ArrayList mExpiredStartAsCallerTokens = new ArrayList<>(); @@ -1512,7 +1512,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public IBinder requestStartActivityPermissionToken(IBinder delegatorToken) { + public IBinder requestStartActivityPermissionToken(ComponentName componentName) { int callingUid = Binder.getCallingUid(); if (UserHandle.getAppId(callingUid) != SYSTEM_UID) { throw new SecurityException("Only the system process can request a permission token, " @@ -1520,7 +1520,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } IBinder permissionToken = new Binder(); synchronized (mGlobalLock) { - mStartActivitySources.put(permissionToken, delegatorToken); + mStartActivitySources.put(permissionToken, componentName); } Message expireMsg = PooledLambda.obtainMessage( @@ -1545,7 +1545,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // 1) The caller is an activity that is part of the core framework, and then only when it // is running as the system. // 2) The caller provides a valid permissionToken. Permission tokens are one-time use and - // can only be requested by a system activity, which may then delegate this call to + // can only be requested from system uid, which may then delegate this call to // another app. final ActivityRecord sourceRecord; final int targetUid; @@ -1556,18 +1556,26 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (resultTo == null) { throw new SecurityException("Must be called from an activity"); } - final IBinder sourceToken; + + sourceRecord = ActivityRecord.isInAnyTask(resultTo); + if (sourceRecord == null) { + throw new SecurityException("Called with bad activity token: " + resultTo); + } + if (sourceRecord.app == null) { + throw new SecurityException("Called without a process attached to activity"); + } + + final ComponentName componentName; if (permissionToken != null) { // To even attempt to use a permissionToken, an app must also have this signature // permission. mAmInternal.enforceCallingPermission( android.Manifest.permission.START_ACTIVITY_AS_CALLER, "startActivityAsCaller"); - // If called with a permissionToken, we want the sourceRecord from the delegator - // activity that requested this token. - sourceToken = mStartActivitySources.remove(permissionToken); - if (sourceToken == null) { - // Invalid permissionToken, check if it recently expired. + // If called with a permissionToken, the caller must be the same component that + // was allowed to use the permissionToken. + componentName = mStartActivitySources.remove(permissionToken); + if (!sourceRecord.mActivityComponent.equals(componentName)) { if (mExpiredStartAsCallerTokens.contains(permissionToken)) { throw new SecurityException("Called with expired permission token: " + permissionToken); @@ -1577,33 +1585,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } } else { - // This method was called directly by the source. - sourceToken = resultTo; - } - - sourceRecord = ActivityRecord.isInAnyTask(sourceToken); - if (sourceRecord == null) { - throw new SecurityException("Called with bad activity token: " + sourceToken); - } - if (sourceRecord.app == null) { - throw new SecurityException("Called without a process attached to activity"); - } - - // Whether called directly or from a delegate, the source activity must be from the - // android package. - if (!sourceRecord.info.packageName.equals("android")) { - throw new SecurityException("Must be called from an activity that is " - + "declared in the android package"); - } - - if (UserHandle.getAppId(sourceRecord.app.mUid) != SYSTEM_UID) { - // This is still okay, as long as this activity is running under the - // uid of the original calling activity. - if (sourceRecord.app.mUid != sourceRecord.launchedFromUid) { - throw new SecurityException( - "Calling activity in uid " + sourceRecord.app.mUid - + " must be system uid or original calling uid " - + sourceRecord.launchedFromUid); + // Whether called directly or from a delegate, the source activity must be from the + // android package. + if (!sourceRecord.info.packageName.equals("android")) { + throw new SecurityException("Must be called from an activity that is " + + "declared in the android package"); + } + if (UserHandle.getAppId(sourceRecord.app.mUid) != SYSTEM_UID) { + // This is still okay, as long as this activity is running under the + // uid of the original calling activity. + if (sourceRecord.app.mUid != sourceRecord.launchedFromUid) { + throw new SecurityException( + "Calling activity in uid " + sourceRecord.app.mUid + + " must be system uid or original calling uid " + + sourceRecord.launchedFromUid); + } } } if (ignoreTargetSecurity) {