Merge "Remove permission token from startActivityAsCaller" into tm-dev
This commit is contained in:
@@ -5707,7 +5707,6 @@ public class Activity extends ContextThemeWrapper
|
||||
* their launch had come from the original activity.
|
||||
* @param intent The Intent to start.
|
||||
* @param options ActivityOptions or null.
|
||||
* @param permissionToken Token received from the system that permits this call to be made.
|
||||
* @param ignoreTargetSecurity If true, the activity manager will not check whether the
|
||||
* caller it is doing the start is, is actually allowed to start the target activity.
|
||||
* If you set this to true, you must set an explicit component in the Intent and do any
|
||||
@@ -5716,18 +5715,18 @@ public class Activity extends ContextThemeWrapper
|
||||
* @hide
|
||||
*/
|
||||
public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
|
||||
IBinder permissionToken, boolean ignoreTargetSecurity, int userId) {
|
||||
startActivityAsCaller(intent, options, permissionToken, ignoreTargetSecurity, userId, -1);
|
||||
boolean ignoreTargetSecurity, int userId) {
|
||||
startActivityAsCaller(intent, options, ignoreTargetSecurity, userId, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #startActivityAsCaller(Intent, Bundle, IBinder, boolean, int)
|
||||
* @see #startActivityAsCaller(Intent, Bundle, boolean, int)
|
||||
* @param requestCode The request code used for returning a result or -1 if no result should be
|
||||
* returned.
|
||||
* @hide
|
||||
*/
|
||||
public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
|
||||
IBinder permissionToken, boolean ignoreTargetSecurity, int userId, int requestCode) {
|
||||
boolean ignoreTargetSecurity, int userId, int requestCode) {
|
||||
if (mParent != null) {
|
||||
throw new RuntimeException("Can't be called from a child");
|
||||
}
|
||||
@@ -5735,8 +5734,7 @@ public class Activity extends ContextThemeWrapper
|
||||
Instrumentation.ActivityResult ar =
|
||||
mInstrumentation.execStartActivityAsCaller(
|
||||
this, mMainThread.getApplicationThread(), mToken, this,
|
||||
intent, requestCode, options, permissionToken, ignoreTargetSecurity,
|
||||
userId);
|
||||
intent, requestCode, options, ignoreTargetSecurity, userId);
|
||||
if (ar != null) {
|
||||
mMainThread.sendActivityResult(
|
||||
mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
|
||||
|
||||
@@ -105,14 +105,6 @@ public class ActivityTaskManager {
|
||||
public static final int RESIZE_MODE_USER_FORCED =
|
||||
RESIZE_MODE_PRESERVE_WINDOW | RESIZE_MODE_FORCED;
|
||||
|
||||
/**
|
||||
* Extra included on intents that are delegating the call to
|
||||
* ActivityManager#startActivityAsCaller to another app. This token is necessary for that call
|
||||
* to succeed. Type is IBinder.
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PERMISSION_TOKEN = "android.app.extra.PERMISSION_TOKEN";
|
||||
|
||||
/**
|
||||
* Extra included on intents that contain an EXTRA_INTENT, with options that the contained
|
||||
* intent may want to be started with. Type is Bundle.
|
||||
|
||||
@@ -141,7 +141,7 @@ interface IActivityTaskManager {
|
||||
int startActivityAsCaller(in IApplicationThread caller, in String callingPackage,
|
||||
in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
|
||||
int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
|
||||
IBinder permissionToken, boolean ignoreTargetSecurity, int userId);
|
||||
boolean ignoreTargetSecurity, int userId);
|
||||
|
||||
boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType,
|
||||
int userId);
|
||||
@@ -182,18 +182,6 @@ interface IActivityTaskManager {
|
||||
int addAppTask(in IBinder activityToken, in Intent intent,
|
||||
in ActivityManager.TaskDescription description, in Bitmap thumbnail);
|
||||
Point getAppTaskThumbnailSize();
|
||||
/**
|
||||
* Only callable from the system. This token grants a temporary permission to call
|
||||
* #startActivityAsCaller. The token will time out after START_AS_CALLER_TOKEN_TIMEOUT
|
||||
* if it is not used.
|
||||
*
|
||||
* @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 ComponentName componentName);
|
||||
|
||||
oneway void releaseSomeActivities(in IApplicationThread app);
|
||||
Bitmap getTaskDescriptionIcon(in String filename, int userId);
|
||||
|
||||
@@ -1999,7 +1999,7 @@ public class Instrumentation {
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public ActivityResult execStartActivityAsCaller(
|
||||
Context who, IBinder contextThread, IBinder token, Activity target,
|
||||
Intent intent, int requestCode, Bundle options, IBinder permissionToken,
|
||||
Intent intent, int requestCode, Bundle options,
|
||||
boolean ignoreTargetSecurity, int userId) {
|
||||
IApplicationThread whoThread = (IApplicationThread) contextThread;
|
||||
if (mActivityMonitors != null) {
|
||||
@@ -2034,7 +2034,7 @@ public class Instrumentation {
|
||||
.startActivityAsCaller(whoThread, who.getOpPackageName(), intent,
|
||||
intent.resolveTypeIfNeeded(who.getContentResolver()),
|
||||
token, target != null ? target.mEmbeddedID : null,
|
||||
requestCode, 0, null, options, permissionToken,
|
||||
requestCode, 0, null, options,
|
||||
ignoreTargetSecurity, userId);
|
||||
checkStartActivityResult(result, intent);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -51,7 +51,6 @@ public final class GameSessionTrampolineActivity extends Activity {
|
||||
startActivityAsCaller(
|
||||
getIntent().getParcelableExtra(INTENT_KEY),
|
||||
getIntent().getBundleExtra(OPTIONS_KEY),
|
||||
null,
|
||||
false,
|
||||
getUserId(),
|
||||
REQUEST_CODE);
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.SharedElementCallback;
|
||||
import android.app.prediction.AppPredictionContext;
|
||||
import android.app.prediction.AppPredictionManager;
|
||||
@@ -71,11 +70,9 @@ import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PatternMatcher;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -761,25 +758,17 @@ public class ChooserActivity extends ResolverActivity implements
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
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);
|
||||
delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
|
||||
Intent delegationIntent = new Intent();
|
||||
final ComponentName delegateActivity = ComponentName.unflattenFromString(
|
||||
Resources.getSystem().getString(R.string.config_chooserActivity));
|
||||
delegationIntent.setComponent(delegateActivity);
|
||||
delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent());
|
||||
delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
|
||||
|
||||
// Don't close until the delegate finishes, or the token will be invalidated.
|
||||
mAwaitingDelegateResponse = true;
|
||||
startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
return false;
|
||||
// Don't close until the delegate finishes, or the token will be invalidated.
|
||||
mAwaitingDelegateResponse = true;
|
||||
startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -207,7 +207,6 @@ public class IntentForwarderActivity extends Activity {
|
||||
startActivityAsCaller(
|
||||
newIntent,
|
||||
/* options= */ null,
|
||||
/* permissionToken= */ null,
|
||||
/* ignoreTargetSecurity= */ false,
|
||||
userId);
|
||||
} catch (RuntimeException e) {
|
||||
@@ -231,7 +230,7 @@ public class IntentForwarderActivity extends Activity {
|
||||
return;
|
||||
}
|
||||
sanitizeIntent(innerIntent);
|
||||
startActivityAsCaller(intentReceived, null, null, false, getUserId());
|
||||
startActivityAsCaller(intentReceived, null, false, getUserId());
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -251,7 +250,7 @@ public class IntentForwarderActivity extends Activity {
|
||||
sanitizeIntent(intentReceived);
|
||||
intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile);
|
||||
intentReceived.putExtra(EXTRA_CALLING_USER, UserHandle.of(callingUserId));
|
||||
startActivityAsCaller(intentReceived, null, null, false, userId);
|
||||
startActivityAsCaller(intentReceived, null, false, userId);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
@@ -1463,7 +1463,7 @@ public class ResolverActivity extends Activity implements
|
||||
int userId) {
|
||||
// Note: this method will be overridden in the delegate implementation to use the passed-in
|
||||
// permission token.
|
||||
startActivityAsCaller(intent, options, null, false, userId);
|
||||
startActivityAsCaller(intent, options, false, userId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ import android.content.pm.UserInfo;
|
||||
import android.metrics.LogMaker;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -649,7 +648,7 @@ public class IntentForwarderActivityTest {
|
||||
|
||||
@Override
|
||||
public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
|
||||
IBinder permissionToken, boolean ignoreTargetSecurity, int userId) {
|
||||
boolean ignoreTargetSecurity, int userId) {
|
||||
mStartActivityIntent = intent;
|
||||
mUserIdActivityLaunchedIn = userId;
|
||||
}
|
||||
|
||||
@@ -21,14 +21,11 @@ import static com.android.server.wm.ActivityInterceptorCallback.INTENT_RESOLVER_
|
||||
import android.Manifest;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||
@@ -39,10 +36,8 @@ import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
|
||||
/**
|
||||
* Service to register an {@code ActivityInterceptorCallback} that modifies any {@code Intent}
|
||||
* that's being used to launch a user-space {@code ChooserActivity}, by adding
|
||||
* EXTRA_PERMISSION_TOKEN, a Binder representing a single-use-only permission to invoke the
|
||||
* #startActivityAsCaller() API (which normally isn't available in user-space); and setting the
|
||||
* destination component to the delegated component when appropriate.
|
||||
* that's being used to launch a user-space {@code ChooserActivity} by setting the destination
|
||||
* component to the delegated component when appropriate.
|
||||
*/
|
||||
public final class IntentResolverInterceptor {
|
||||
private static final String TAG = "IntentResolverIntercept";
|
||||
@@ -92,7 +87,6 @@ public final class IntentResolverInterceptor {
|
||||
|
||||
private Intent modifyChooserIntent(Intent intent) {
|
||||
intent.setComponent(getUnbundledChooserComponentName());
|
||||
addStartActivityPermissionTokenToIntent(intent, getUnbundledChooserComponentName());
|
||||
return intent;
|
||||
}
|
||||
|
||||
@@ -103,18 +97,6 @@ public final class IntentResolverInterceptor {
|
||||
|| targetComponent.equals(getUnbundledChooserComponentName());
|
||||
}
|
||||
|
||||
private static Intent addStartActivityPermissionTokenToIntent(
|
||||
Intent intent, ComponentName grantee) {
|
||||
try {
|
||||
intent.putExtra(
|
||||
ActivityTaskManager.EXTRA_PERMISSION_TOKEN,
|
||||
ActivityTaskManager.getService().requestStartActivityPermissionToken(grantee));
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Failed to add permission token to chooser intent");
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
|
||||
private static ComponentName getSystemChooserComponentName() {
|
||||
return new ComponentName("android", "com.android.internal.app.ChooserActivity");
|
||||
}
|
||||
|
||||
@@ -421,30 +421,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
// How long to wait in getAutofillAssistStructure() for the activity to respond with the result.
|
||||
private static final int PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT = 2000;
|
||||
|
||||
// Permission tokens are used to temporarily granted a trusted app the ability to call
|
||||
// #startActivityAsCaller. A client is expected to dump its token after this time has elapsed,
|
||||
// showing any appropriate error messages to the user.
|
||||
private static final long START_AS_CALLER_TOKEN_TIMEOUT =
|
||||
10 * MINUTE_IN_MILLIS;
|
||||
|
||||
// How long before the service actually expires a token. This is slightly longer than
|
||||
// START_AS_CALLER_TOKEN_TIMEOUT, to provide a buffer so clients will rarely encounter the
|
||||
// expiration exception.
|
||||
private static final long START_AS_CALLER_TOKEN_TIMEOUT_IMPL =
|
||||
START_AS_CALLER_TOKEN_TIMEOUT + 2 * 1000;
|
||||
|
||||
// How long the service will remember expired tokens, for the purpose of providing error
|
||||
// messaging when a client uses an expired token.
|
||||
private static final long START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT =
|
||||
START_AS_CALLER_TOKEN_TIMEOUT_IMPL + 20 * MINUTE_IN_MILLIS;
|
||||
|
||||
// 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<>();
|
||||
|
||||
private final ArrayList<PendingAssistExtras> mPendingAssistExtras = new ArrayList<>();
|
||||
|
||||
// Keeps track of the active voice interaction service component, notified from
|
||||
@@ -1546,42 +1522,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
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, "
|
||||
+ "received request from uid: " + callingUid);
|
||||
}
|
||||
IBinder permissionToken = new Binder();
|
||||
synchronized (mGlobalLock) {
|
||||
mStartActivitySources.put(permissionToken, componentName);
|
||||
}
|
||||
|
||||
Message expireMsg = PooledLambda.obtainMessage(
|
||||
ActivityTaskManagerService::expireStartAsCallerTokenMsg, this, permissionToken);
|
||||
mUiHandler.sendMessageDelayed(expireMsg, START_AS_CALLER_TOKEN_TIMEOUT_IMPL);
|
||||
|
||||
Message forgetMsg = PooledLambda.obtainMessage(
|
||||
ActivityTaskManagerService::forgetStartAsCallerTokenMsg, this, permissionToken);
|
||||
mUiHandler.sendMessageDelayed(forgetMsg, START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT);
|
||||
|
||||
return permissionToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int startActivityAsCaller(IApplicationThread caller, String callingPackage,
|
||||
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
|
||||
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, IBinder permissionToken,
|
||||
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions,
|
||||
boolean ignoreTargetSecurity, int userId) {
|
||||
// This is very dangerous -- it allows you to perform a start activity (including
|
||||
// permission grants) as any app that may launch one of your own activities. So we only
|
||||
// allow this in two cases:
|
||||
// 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 from system uid, which may then delegate this call to
|
||||
// another app.
|
||||
// 1) The calling process holds the signature permission START_ACTIVITY_AS_CALLER
|
||||
//
|
||||
// 2) The calling process is an activity belonging to the package "android" which is
|
||||
// running as UID_SYSTEM or as the target UID (the activity which started the activity
|
||||
// calling this method).
|
||||
|
||||
final ActivityRecord sourceRecord;
|
||||
final int targetUid;
|
||||
final String targetPackage;
|
||||
@@ -1600,26 +1554,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
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, 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);
|
||||
} else {
|
||||
throw new SecurityException("Called with invalid permission token: "
|
||||
+ permissionToken);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (checkCallingPermission(Manifest.permission.START_ACTIVITY_AS_CALLER)
|
||||
!= PERMISSION_GRANTED) {
|
||||
// Whether called directly or from a delegate, the source activity must be from the
|
||||
// android package.
|
||||
if (!sourceRecord.info.packageName.equals("android")) {
|
||||
@@ -4453,15 +4389,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
Settings.System.putConfigurationForUser(resolver, config, userId);
|
||||
}
|
||||
|
||||
private void expireStartAsCallerTokenMsg(IBinder permissionToken) {
|
||||
mStartActivitySources.remove(permissionToken);
|
||||
mExpiredStartAsCallerTokens.add(permissionToken);
|
||||
}
|
||||
|
||||
private void forgetStartAsCallerTokenMsg(IBinder permissionToken) {
|
||||
mExpiredStartAsCallerTokens.remove(permissionToken);
|
||||
}
|
||||
|
||||
boolean isActivityStartsLoggingEnabled() {
|
||||
return mAmInternal.isActivityStartsLoggingEnabled();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user