Merge "Allow requesting start-activity-permission-token for an activity"

This commit is contained in:
Louis Chang
2022-01-12 01:04:34 +00:00
committed by Android (Google) Code Review
4 changed files with 44 additions and 49 deletions

View File

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

View File

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

View File

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

View File

@@ -437,9 +437,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<IBinder, IBinder> 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<IBinder, ComponentName> mStartActivitySources = new HashMap<>();
// Permission tokens that have expired, but we remember for error reporting.
final ArrayList<IBinder> mExpiredStartAsCallerTokens = new ArrayList<>();
@@ -1513,7 +1513,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, "
@@ -1521,7 +1521,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(
@@ -1546,7 +1546,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;
@@ -1557,18 +1557,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);
@@ -1578,33 +1586,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) {