diff options
author | Jeff Sharkey <jsharkey@google.com> | 2020-05-30 00:11:42 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-05-30 00:11:42 +0000 |
commit | b9a239bef34ab52350924f3a17d59201b6192a69 (patch) | |
tree | d8e46f49fdbf003b0818dcc098db63bbf1ab0b21 | |
parent | aa5f48cffe92dd93bcae333d7b9e7a29595480b2 (diff) | |
parent | 307ea7a2fef3154683a013d6af565f311524de93 (diff) |
Merge changes from topic "apr12" into rvc-dev
* changes:
Collect NeededUriGrants without holding locks.
Initial splitting of calculation and grants.
17 files changed, 220 insertions, 157 deletions
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index 043f657b7f2c..1804b7f66fa2 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -45,6 +45,7 @@ import android.telephony.TelephonyManager; import android.util.Slog; import com.android.internal.telephony.IMms; +import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import java.util.List; @@ -512,9 +513,11 @@ public class MmsServiceBroker extends SystemService { long token = Binder.clearCallingIdentity(); try { - LocalServices.getService(UriGrantsManagerInternal.class) - .grantUriPermissionFromIntent(callingUid, PHONE_PACKAGE_NAME, - grantIntent, UserHandle.USER_SYSTEM); + final UriGrantsManagerInternal ugm = LocalServices + .getService(UriGrantsManagerInternal.class); + final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent( + grantIntent, callingUid, PHONE_PACKAGE_NAME, UserHandle.USER_SYSTEM); + ugm.grantUriPermissionUncheckedFromIntent(needed, null); // Grant permission for the carrier app. Intent intent = new Intent(action); @@ -524,9 +527,10 @@ public class MmsServiceBroker extends SystemService { .getCarrierPackageNamesForIntentAndPhone( intent, getPhoneIdFromSubId(subId)); if (carrierPackages != null && carrierPackages.size() == 1) { - LocalServices.getService(UriGrantsManagerInternal.class) - .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0), - grantIntent, UserHandle.USER_SYSTEM); + final NeededUriGrants carrierNeeded = ugm.checkGrantUriPermissionFromIntent( + grantIntent, callingUid, carrierPackages.get(0), + UserHandle.USER_SYSTEM); + ugm.grantUriPermissionUncheckedFromIntent(carrierNeeded, null); } } finally { Binder.restoreCallingIdentity(token); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 8cdffb7b1b13..5046070647d6 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -590,7 +590,7 @@ public final class ActiveServices { } NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent( - callingUid, r.packageName, service, service.getFlags(), null, r.userId); + service, callingUid, r.packageName, r.userId); // If permissions need a review before any of the app components can run, // we do not start the service and launch a review activity if the calling app diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a5bb4733a509..b2262c0a06c7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -365,6 +365,7 @@ import com.android.server.job.JobSchedulerInternal; import com.android.server.pm.Installer; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.uri.GrantUri; +import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.utils.PriorityDump; import com.android.server.utils.TimingsTraceAndSlog; @@ -6511,17 +6512,19 @@ public class ActivityManagerService extends IActivityManager.Stub if (targetPkg == null) { throw new IllegalArgumentException("null target"); } - if (grantUri == null) { - throw new IllegalArgumentException("null uri"); - } Preconditions.checkFlagsArgument(modeFlags, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); - mUgmInternal.grantUriPermission(r.uid, targetPkg, grantUri, modeFlags, null, - UserHandle.getUserId(r.uid)); + final Intent intent = new Intent(); + intent.setData(uri); + intent.setFlags(modeFlags); + + final NeededUriGrants needed = mUgmInternal.checkGrantUriPermissionFromIntent(intent, + r.uid, targetPkg, UserHandle.getUserId(r.uid)); + mUgmInternal.grantUriPermissionUncheckedFromIntent(needed, null); } } diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java index 8afb87f3020d..cdb61995c336 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java @@ -31,28 +31,35 @@ import java.io.PrintWriter; public interface UriGrantsManagerInternal { void onSystemReady(); void removeUriPermissionIfNeeded(UriPermission perm); - void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri, - final int modeFlags, UriPermissionOwner owner, int targetUserId); + void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri, final int modeFlags); + boolean checkUriPermission(GrantUri grantUri, int uid, final int modeFlags); - int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri grantUri, - final int modeFlags, int lastTargetUid); int checkGrantUriPermission( int callingUid, String targetPkg, Uri uri, int modeFlags, int userId); - NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid, - String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId); + /** - * Grant Uri permissions from one app to another. This method only extends - * permission grants if {@code callingUid} has permission to them. + * Calculate the set of permission grants that would be needed to extend + * access for the given {@link Intent} to the given target package. + * + * @throws SecurityException if the caller doesn't have permission to the + * {@link Intent} data, or if the underlying provider doesn't + * allow permissions to be granted. + */ + NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid, + String targetPkg, int targetUserId); + + /** + * Extend a previously calculated set of permissions grants to the given + * owner. All security checks will have already been performed as part of + * calculating {@link NeededUriGrants}. */ - void grantUriPermissionFromIntent(int callingUid, - String targetPkg, Intent intent, int targetUserId); - void grantUriPermissionFromIntent(int callingUid, - String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId); void grantUriPermissionUncheckedFromIntent( NeededUriGrants needed, UriPermissionOwner owner); + IBinder newUriPermissionOwner(String name); + /** * Remove any {@link UriPermission} granted <em>from</em> or <em>to</em> the * given package. diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java index 72cdf4afb007..9476e9260c73 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java @@ -635,17 +635,6 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { return needed; } - void grantUriPermissionFromIntent(int callingUid, - String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId) { - NeededUriGrants needed = checkGrantUriPermissionFromIntent(callingUid, targetPkg, - intent, intent != null ? intent.getFlags() : 0, null, targetUserId); - if (needed == null) { - return; - } - - grantUriPermissionUncheckedFromIntent(needed, owner); - } - void readGrantedUriPermissions() { if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()"); @@ -1326,15 +1315,6 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { } @Override - public void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri, - int modeFlags, UriPermissionOwner owner, int targetUserId) { - synchronized (mLock) { - UriGrantsManagerService.this.grantUriPermission( - callingUid, targetPkg, grantUri, modeFlags, owner, targetUserId); - } - } - - @Override public void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri, int modeFlags) { synchronized (mLock) { @@ -1351,15 +1331,6 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { } @Override - public int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri uri, - int modeFlags, int userId) { - synchronized (mLock) { - return UriGrantsManagerService.this.checkGrantUriPermission( - callingUid, targetPkg, uri, modeFlags, userId); - } - } - - @Override public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags, int userId) { enforceNotIsolatedCaller("checkGrantUriPermission"); @@ -1370,29 +1341,12 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { } @Override - public NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid, String targetPkg, - Intent intent, int mode, NeededUriGrants needed, int targetUserId) { + public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid, + String targetPkg, int targetUserId) { synchronized (mLock) { + final int mode = (intent != null) ? intent.getFlags() : 0; return UriGrantsManagerService.this.checkGrantUriPermissionFromIntent( - callingUid, targetPkg, intent, mode, needed, targetUserId); - } - } - - @Override - public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent, - int targetUserId) { - synchronized (mLock) { - UriGrantsManagerService.this.grantUriPermissionFromIntent( - callingUid, targetPkg, intent, null, targetUserId); - } - } - - @Override - public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent, - UriPermissionOwner owner, int targetUserId) { - synchronized (mLock) { - UriGrantsManagerService.this.grantUriPermissionFromIntent( - callingUid, targetPkg, intent, owner, targetUserId); + callingUid, targetPkg, intent, mode, null, targetUserId); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5ef9d9e627ff..7c33c7cf6398 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -306,6 +306,7 @@ import com.android.server.am.PendingIntentRecord; import com.android.server.display.color.ColorDisplayService; import com.android.server.policy.WindowManagerPolicy; import com.android.server.protolog.common.ProtoLog; +import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; import com.android.server.wm.ActivityStack.ActivityState; @@ -2435,7 +2436,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Sets the result for activity that started this one, clears the references to activities * started for result from this one, and clears new intents. */ - private void finishActivityResults(int resultCode, Intent resultData) { + private void finishActivityResults(int resultCode, Intent resultData, + NeededUriGrants resultGrants) { // Send the result if needed if (resultTo != null) { if (DEBUG_RESULTS) { @@ -2449,9 +2451,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } if (info.applicationInfo.uid > 0) { - mAtmService.mUgmInternal.grantUriPermissionFromIntent(info.applicationInfo.uid, - resultTo.packageName, resultData, - resultTo.getUriPermissionsLocked(), resultTo.mUserId); + mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants, + resultTo.getUriPermissionsLocked()); } resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData); resultTo = null; @@ -2487,7 +2488,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * See {@link #finishIfPossible(int, Intent, String, boolean)} */ @FinishRequest int finishIfPossible(String reason, boolean oomAdj) { - return finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason, oomAdj); + return finishIfPossible(Activity.RESULT_CANCELED, + null /* resultData */, null /* resultGrants */, reason, oomAdj); } /** @@ -2501,8 +2503,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * {@link #FINISH_RESULT_CANCELLED} if activity is already finishing or in invalid state and the * request to finish it was not ignored. */ - @FinishRequest int finishIfPossible(int resultCode, Intent resultData, String reason, - boolean oomAdj) { + @FinishRequest int finishIfPossible(int resultCode, Intent resultData, + NeededUriGrants resultGrants, String reason, boolean oomAdj) { if (DEBUG_RESULTS || DEBUG_STATES) { Slog.v(TAG_STATES, "Finishing activity r=" + this + ", result=" + resultCode + ", data=" + resultData + ", reason=" + reason); @@ -2554,7 +2556,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A shouldAdjustGlobalFocus); } - finishActivityResults(resultCode, resultData); + finishActivityResults(resultCode, resultData, resultGrants); final boolean endTask = task.getActivityBelow(this) == null && !task.isClearingToReuseTask(); @@ -2912,7 +2914,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */ void removeFromHistory(String reason) { - finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */); + finishActivityResults(Activity.RESULT_CANCELED, + null /* resultData */, null /* resultGrants */); makeFinishingLocked(); if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE) { Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack callers=" @@ -3662,10 +3665,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void sendResult(int callingUid, String resultWho, int requestCode, int resultCode, - Intent data) { + Intent data, NeededUriGrants dataGrants) { if (callingUid > 0) { - mAtmService.mUgmInternal.grantUriPermissionFromIntent(callingUid, packageName, - data, getUriPermissionsLocked(), mUserId); + mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants, + getUriPermissionsLocked()); } if (DEBUG_RESULTS) { @@ -3704,10 +3707,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Deliver a new Intent to an existing activity, so that its onNewIntent() * method will be called at the proper time. */ - final void deliverNewIntentLocked(int callingUid, Intent intent, String referrer) { + final void deliverNewIntentLocked(int callingUid, Intent intent, NeededUriGrants intentGrants, + String referrer) { // The activity now gets access to the data associated with this Intent. - mAtmService.mUgmInternal.grantUriPermissionFromIntent(callingUid, packageName, - intent, getUriPermissionsLocked(), mUserId); + mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants, + getUriPermissionsLocked()); final ReferrerIntent rintent = new ReferrerIntent(intent, referrer); boolean unsent = true; final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping(); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index d0f6465a6bc1..00b2a58dbe8f 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -156,6 +156,7 @@ import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService; import com.android.server.am.ActivityManagerService.ItemMatcher; import com.android.server.am.AppTimeTracker; +import com.android.server.uri.NeededUriGrants; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -2353,8 +2354,8 @@ class ActivityStack extends Task { return false; } - boolean navigateUpTo(ActivityRecord srec, Intent destIntent, int resultCode, - Intent resultData) { + boolean navigateUpTo(ActivityRecord srec, Intent destIntent, NeededUriGrants destGrants, + int resultCode, Intent resultData, NeededUriGrants resultGrants) { if (!srec.attachedToProcess()) { // Nothing to do if the caller is not attached, because this method should be called // from an alive activity. @@ -2405,12 +2406,14 @@ class ActivityStack extends Task { resultCodeHolder[0] = resultCode; final Intent[] resultDataHolder = new Intent[1]; resultDataHolder[0] = resultData; + final NeededUriGrants[] resultGrantsHolder = new NeededUriGrants[1]; + resultGrantsHolder[0] = resultGrants; final ActivityRecord finalParent = parent; task.forAllActivities((ar) -> { if (ar == finalParent) return true; - ar.finishIfPossible( - resultCodeHolder[0], resultDataHolder[0], "navigate-up", true /* oomAdj */); + ar.finishIfPossible(resultCodeHolder[0], resultDataHolder[0], resultGrantsHolder[0], + "navigate-up", true /* oomAdj */); // Only return the supplied result for the first activity finished resultCodeHolder[0] = Activity.RESULT_CANCELED; resultDataHolder[0] = null; @@ -2427,7 +2430,7 @@ class ActivityStack extends Task { parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); + parent.deliverNewIntentLocked(callingUid, destIntent, destGrants, srec.packageName); } else { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( @@ -2451,7 +2454,8 @@ class ActivityStack extends Task { } catch (RemoteException e) { foundParentInTask = false; } - parent.finishIfPossible(resultCode, resultData, "navigate-top", true /* oomAdj */); + parent.finishIfPossible(resultCode, resultData, resultGrants, + "navigate-top", true /* oomAdj */); } } Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 80ca95fe2ebd..b7ca1a9aeab8 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -140,6 +140,7 @@ import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.am.ActivityManagerService; import com.android.server.am.UserState; +import com.android.server.uri.NeededUriGrants; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import java.io.FileDescriptor; @@ -380,14 +381,17 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final int startFlags; final ActivityStack stack; final WindowProcessController callerApp; + final NeededUriGrants intentGrants; - PendingActivityLaunch(ActivityRecord _r, ActivityRecord _sourceRecord, - int _startFlags, ActivityStack _stack, WindowProcessController app) { - r = _r; - sourceRecord = _sourceRecord; - startFlags = _startFlags; - stack = _stack; - callerApp = app; + PendingActivityLaunch(ActivityRecord r, ActivityRecord sourceRecord, + int startFlags, ActivityStack stack, WindowProcessController callerApp, + NeededUriGrants intentGrants) { + this.r = r; + this.sourceRecord = sourceRecord; + this.startFlags = startFlags; + this.stack = stack; + this.callerApp = callerApp; + this.intentGrants = intentGrants; } void sendErrorResult(String message) { @@ -1004,7 +1008,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) { if (resultRecord != null) { resultRecord.sendResult(INVALID_UID, resultWho, requestCode, - Activity.RESULT_CANCELED, null /* data */); + Activity.RESULT_CANCELED, null /* data */, null /* dataGrants */); } final String msg; if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) { diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index c4ccd00d9b0a..6fbfa68d9309 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -517,7 +517,7 @@ public class ActivityStartController { "pendingActivityLaunch"); try { starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, - resume, pal.r.pendingOptions, null); + resume, pal.r.pendingOptions, null, pal.intentGrants); } catch (Exception e) { Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e); pal.sendErrorResult(e.getMessage()); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index bcdd6e39e85c..daa97b56ed66 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -118,6 +118,7 @@ import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; import com.android.server.am.PendingIntentRecord; import com.android.server.pm.InstantAppResolver; +import com.android.server.uri.NeededUriGrants; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch; import com.android.server.wm.LaunchParamsController.LaunchParams; @@ -310,6 +311,7 @@ class ActivityStarter { IApplicationThread caller; Intent intent; + NeededUriGrants intentGrants; // A copy of the original requested intent, in case for ephemeral app launch. Intent ephemeralIntent; String resolvedType; @@ -361,6 +363,7 @@ class ActivityStarter { void reset() { caller = null; intent = null; + intentGrants = null; ephemeralIntent = null; resolvedType = null; activityInfo = null; @@ -400,6 +403,7 @@ class ActivityStarter { void set(Request request) { caller = request.caller; intent = request.intent; + intentGrants = request.intentGrants; ephemeralIntent = request.ephemeralIntent; resolvedType = request.resolvedType; activityInfo = request.activityInfo; @@ -454,6 +458,20 @@ class ActivityStarter { callingPid = callingUid = -1; } + // To determine the set of needed Uri permission grants, we need the + // "resolved" calling UID, where we try our best to identify the + // actual caller that is starting this activity + int resolvedCallingUid = callingUid; + if (caller != null) { + synchronized (supervisor.mService.mGlobalLock) { + final WindowProcessController callerApp = supervisor.mService + .getProcessController(caller); + if (callerApp != null) { + resolvedCallingUid = callerApp.mInfo.uid; + } + } + } + // Save a copy in case ephemeral needs it ephemeralIntent = new Intent(intent); // Don't modify the client's object! @@ -503,6 +521,13 @@ class ActivityStarter { // Collect information about the target of the Intent. activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags, profilerInfo); + + // Carefully collect grants without holding lock + if (activityInfo != null) { + intentGrants = supervisor.mService.mUgmInternal.checkGrantUriPermissionFromIntent( + intent, resolvedCallingUid, activityInfo.applicationInfo.packageName, + UserHandle.getUserId(activityInfo.applicationInfo.uid)); + } } } @@ -577,7 +602,8 @@ class ActivityStarter { */ void startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - int startFlags, boolean doResume, ActivityOptions options, Task inTask) { + int startFlags, boolean doResume, ActivityOptions options, Task inTask, + NeededUriGrants intentGrants) { try { final LaunchingState launchingState = mSupervisor.getActivityMetricsLogger() .notifyActivityLaunching(r.intent, r.resultTo); @@ -586,7 +612,7 @@ class ActivityStarter { mLastStartActivityRecord = r; mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, - false /* restrictedBgActivity */); + false /* restrictedBgActivity */, intentGrants); mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, mLastStartActivityResult, mLastStartActivityRecord); } finally { @@ -813,6 +839,7 @@ class ActivityStarter { final IApplicationThread caller = request.caller; Intent intent = request.intent; + NeededUriGrants intentGrants = request.intentGrants; String resolvedType = request.resolvedType; ActivityInfo aInfo = request.activityInfo; ResolveInfo rInfo = request.resolveInfo; @@ -960,7 +987,7 @@ class ActivityStarter { if (err != START_SUCCESS) { if (resultRecord != null) { resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED, - null /* data */); + null /* data */, null /* dataGrants */); } SafeActivityOptions.abort(options); return err; @@ -1022,12 +1049,16 @@ class ActivityStarter { callingPid = mInterceptor.mCallingPid; callingUid = mInterceptor.mCallingUid; checkedOptions = mInterceptor.mActivityOptions; + + // The interception target shouldn't get any permission grants + // intended for the original destination + intentGrants = null; } if (abort) { if (resultRecord != null) { resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED, - null /* data */); + null /* data */, null /* dataGrants */); } // We pretend to the caller that it was really started, but they will just get a // cancel result. @@ -1073,6 +1104,10 @@ class ActivityStarter { } intent = newIntent; + // The permissions review target shouldn't get any permission + // grants intended for the original destination + intentGrants = null; + resolvedType = null; callingUid = realCallingUid; callingPid = realCallingPid; @@ -1105,6 +1140,10 @@ class ActivityStarter { callingUid = realCallingUid; callingPid = realCallingPid; + // The ephemeral installer shouldn't get any permission grants + // intended for the original destination + intentGrants = null; + aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); } @@ -1131,7 +1170,7 @@ class ActivityStarter { realCallingPid, realCallingUid, "Activity start")) { if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) { mController.addPendingActivityLaunch(new PendingActivityLaunch(r, - sourceRecord, startFlags, stack, callerApp)); + sourceRecord, startFlags, stack, callerApp, intentGrants)); } ActivityOptions.abort(checkedOptions); return ActivityManager.START_SWITCHES_CANCELED; @@ -1143,7 +1182,7 @@ class ActivityStarter { mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, - restrictedBgActivity); + restrictedBgActivity, intentGrants); if (request.outActivity != null) { request.outActivity[0] = mLastStartActivityRecord; @@ -1168,7 +1207,7 @@ class ActivityStarter { int requestCode = r.requestCode; if (resultRecord != null) { resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED, - null /* data */); + null /* data */, null /* dataGrants */); } // We pretend to the caller that it was really started to make it backward compatible, but // they will just get a cancel result. @@ -1470,14 +1509,14 @@ class ActivityStarter { private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, - boolean restrictedBgActivity) { + boolean restrictedBgActivity, NeededUriGrants intentGrants) { int result = START_CANCELED; final ActivityStack startedActivityStack; try { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, - startFlags, doResume, options, inTask, restrictedBgActivity); + startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); startedActivityStack = handleStartResult(r, result); @@ -1545,7 +1584,7 @@ class ActivityStarter { int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, - boolean restrictedBgActivity) { + boolean restrictedBgActivity, NeededUriGrants intentGrants) { setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor, restrictedBgActivity); @@ -1582,7 +1621,7 @@ class ActivityStarter { ? null : targetTask.getTopNonFinishingActivity(); if (targetTaskTop != null) { // Recycle the target task for this launch. - startResult = recycleTask(targetTask, targetTaskTop, reusedTask); + startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants); if (startResult != START_SUCCESS) { return startResult; } @@ -1594,7 +1633,7 @@ class ActivityStarter { // we need to check if it should only be launched once. final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack(); if (topStack != null) { - startResult = deliverToCurrentTopIfNeeded(topStack); + startResult = deliverToCurrentTopIfNeeded(topStack, intentGrants); if (startResult != START_SUCCESS) { return startResult; } @@ -1625,8 +1664,8 @@ class ActivityStarter { } } - mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName, - mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId); + mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants, + mStartActivity.getUriPermissionsLocked()); if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) { // we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs final PackageManagerInternal pmInternal = @@ -1752,7 +1791,8 @@ class ActivityStarter { if (mStartActivity.packageName == null) { if (mStartActivity.resultTo != null) { mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho, - mStartActivity.requestCode, RESULT_CANCELED, null /* data */); + mStartActivity.requestCode, RESULT_CANCELED, + null /* data */, null /* dataGrants */); } ActivityOptions.abort(mOptions); return START_CLASS_NOT_FOUND; @@ -1797,7 +1837,8 @@ class ActivityStarter { * - Determine whether need to add a new activity on top or just brought the task to front. */ @VisibleForTesting - int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) { + int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask, + NeededUriGrants intentGrants) { // Should not recycle task which is from a different user, just adding the starting // activity to the task. if (targetTask.mUserId != mStartActivity.mUserId) { @@ -1857,7 +1898,7 @@ class ActivityStarter { } complyActivityFlags(targetTask, - reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null); + reusedTask != null ? reusedTask.getTopNonFinishingActivity() : null, intentGrants); if (clearTaskForReuse) { // Clear task for re-use so later code to methods @@ -1893,7 +1934,7 @@ class ActivityStarter { * Check if the activity being launched is the same as the one currently at the top and it * should only be launched once. */ - private int deliverToCurrentTopIfNeeded(ActivityStack topStack) { + private int deliverToCurrentTopIfNeeded(ActivityStack topStack, NeededUriGrants intentGrants) { final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop); final boolean dontStart = top != null && mStartActivity.resultTo == null && top.mActivityComponent.equals(mStartActivity.mActivityComponent) @@ -1921,7 +1962,7 @@ class ActivityStarter { return START_RETURN_INTENT_TO_CALLER; } - deliverNewIntent(top); + deliverNewIntent(top, intentGrants); // Don't use mStartActivity.task to show the toast. We're not starting a new activity but // reusing 'top'. Fields in mStartActivity may not be fully initialized. @@ -1935,7 +1976,8 @@ class ActivityStarter { * Applying the launching flags to the task, which might clear few or all the activities in the * task. */ - private void complyActivityFlags(Task targetTask, ActivityRecord reusedActivity) { + private void complyActivityFlags(Task targetTask, ActivityRecord reusedActivity, + NeededUriGrants intentGrants) { ActivityRecord targetTaskTop = targetTask.getTopNonFinishingActivity(); final boolean resetTask = reusedActivity != null && (mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0; @@ -1979,7 +2021,7 @@ class ActivityStarter { // so make sure the task now has the identity of the new intent. top.getTask().setIntent(mStartActivity); } - deliverNewIntent(top); + deliverNewIntent(top, intentGrants); } else { // A special case: we need to start the activity because it is not currently // running, and the caller has asked to clear the current task to have this @@ -2005,7 +2047,7 @@ class ActivityStarter { final Task task = act.getTask(); task.moveActivityToFrontLocked(act); act.updateOptionsLocked(mOptions); - deliverNewIntent(act); + deliverNewIntent(act, intentGrants); mTargetStack.mLastPausedActivity = null; } else { mAddingToTask = true; @@ -2025,7 +2067,7 @@ class ActivityStarter { if (targetTaskTop.isRootOfTask()) { targetTaskTop.getTask().setIntent(mStartActivity); } - deliverNewIntent(targetTaskTop); + deliverNewIntent(targetTaskTop, intentGrants); } else if (!targetTask.isSameIntentFilter(mStartActivity)) { // In this case we are launching the root activity of the task, but with a // different intent. We should start a new instance on top. @@ -2233,7 +2275,8 @@ class ActivityStarter { // as normal without a dependency on its originator. Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result."); mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho, - mStartActivity.requestCode, RESULT_CANCELED, null /* data */); + mStartActivity.requestCode, RESULT_CANCELED, + null /* data */, null /* dataGrants */); mStartActivity.resultTo = null; } } @@ -2512,13 +2555,13 @@ class ActivityStarter { } } - private void deliverNewIntent(ActivityRecord activity) { + private void deliverNewIntent(ActivityRecord activity, NeededUriGrants intentGrants) { if (mIntentDelivered) { return; } activity.logStartActivity(EventLogTags.WM_NEW_INTENT, activity.getTask()); - activity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, + activity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, intentGrants, mStartActivity.launchedFromPackage); mIntentDelivered = true; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index fdbb2b25bd39..5f591b54b067 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -270,6 +270,7 @@ import com.android.server.firewall.IntentFirewall; import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.pm.UserManagerService; import com.android.server.policy.PermissionPolicyInternal; +import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.vr.VrManagerInternal; @@ -1672,11 +1673,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { throw new IllegalArgumentException("File descriptors passed in Intent"); } + final ActivityRecord r; synchronized (mGlobalLock) { - final ActivityRecord r = ActivityRecord.isInStackLocked(token); + r = ActivityRecord.isInStackLocked(token); if (r == null) { return true; } + } + + // Carefully collect grants without holding lock + final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo); + + synchronized (mGlobalLock) { // Keep track of the root activity of the task before we finish it final Task tr = r.getTask(); final ActivityRecord rootR = tr.getRootActivity(); @@ -1737,7 +1745,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Explicitly dismissing the activity so reset its relaunch flag. r.mRelaunchReason = RELAUNCH_REASON_NONE; } else { - r.finishIfPossible(resultCode, resultData, "app-request", true /* oomAdj */); + r.finishIfPossible(resultCode, resultData, resultGrants, + "app-request", true /* oomAdj */); res = r.finishing; if (!res) { Slog.i(TAG, "Failed to finish by app-request"); @@ -2258,14 +2267,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode, Intent resultData) { - + final ActivityRecord r; synchronized (mGlobalLock) { - final ActivityRecord r = ActivityRecord.forTokenLocked(token); - if (r != null) { - return r.getRootTask().navigateUpTo( - r, destIntent, resultCode, resultData); + r = ActivityRecord.isInStackLocked(token); + if (r == null) { + return false; } - return false; + } + + // Carefully collect grants without holding lock + final NeededUriGrants destGrants = collectGrants(destIntent, r); + final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo); + + synchronized (mGlobalLock) { + return r.getRootTask().navigateUpTo( + r, destIntent, destGrants, resultCode, resultData, resultGrants); } } @@ -2417,6 +2433,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return r.resultTo; } + private NeededUriGrants collectGrants(Intent intent, ActivityRecord target) { + if (target != null) { + return mUgmInternal.checkGrantUriPermissionFromIntent(intent, + Binder.getCallingUid(), target.packageName, target.mUserId); + } else { + return null; + } + } + @Override public void unhandledBack() { mAmInternal.enforceCallingPermission(android.Manifest.permission.FORCE_BACK, "unhandledBack()"); @@ -6573,12 +6598,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void sendActivityResult(int callingUid, IBinder activityToken, String resultWho, int requestCode, int resultCode, Intent data) { + final ActivityRecord r; synchronized (mGlobalLock) { - final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken); - if (r != null && r.getRootTask() != null) { - r.sendResult(callingUid, resultWho, requestCode, resultCode, data); + r = ActivityRecord.isInStackLocked(activityToken); + if (r == null || r.getRootTask() == null) { + return; } } + + // Carefully collect grants without holding lock + final NeededUriGrants dataGrants = collectGrants(data, r); + + synchronized (mGlobalLock) { + r.sendResult(callingUid, resultWho, requestCode, resultCode, data, dataGrants); + } } @Override diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 7113a15da1bf..345928e17768 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1522,8 +1522,8 @@ class Task extends WindowContainer<WindowContainer> { forAllActivities((r) -> { if (r.finishing) return; // TODO: figure-out how to avoid object creation due to capture of reason variable. - r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason, - false /* oomAdj */); + r.finishIfPossible(Activity.RESULT_CANCELED, + null /* resultData */, null /* resultGrants */, reason, false /* oomAdj */); }); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 8d32d7c970bc..f1064d153814 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -297,6 +297,7 @@ import com.android.server.pm.RestrictionsSet; import com.android.server.pm.UserRestrictionsUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.storage.DeviceStorageMonitorInternal; +import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -8365,10 +8366,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - LocalServices.getService(UriGrantsManagerInternal.class) - .grantUriPermissionFromIntent(Process.SHELL_UID, - mOwners.getDeviceOwnerComponent().getPackageName(), - intent, mOwners.getDeviceOwnerUserId()); + final UriGrantsManagerInternal ugm = LocalServices + .getService(UriGrantsManagerInternal.class); + final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent(intent, + Process.SHELL_UID, mOwners.getDeviceOwnerComponent().getPackageName(), + mOwners.getDeviceOwnerUserId()); + ugm.grantUriPermissionUncheckedFromIntent(needed, null); + mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId())); } } catch (FileNotFoundException e) { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 4f14cd0b6fd9..4ee933a0a5a5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -762,8 +762,8 @@ public class ActivityRecordTests extends ActivityTestsBase { assertTrue(mStack.isTopStackInDisplayArea()); mActivity.setState(RESUMED, "test"); - mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test", - false /* oomAdj */); + mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, + null /* resultGrants */, "test", false /* oomAdj */); assertTrue(stack1.isTopStackInDisplayArea()); } @@ -788,8 +788,8 @@ public class ActivityRecordTests extends ActivityTestsBase { // Finish top activity and verify the next focusable rootable task has adjusted to top. topActivity.setState(RESUMED, "test"); - topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test", - false /* oomAdj */); + topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, + null /* resultGrants */, "test", false /* oomAdj */); assertEquals(mTask, mStack.getTopMostTask()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 64e08c6ef108..37882bb2ba76 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -1281,11 +1281,13 @@ public class ActivityStackTests extends ActivityTestsBase { secondActivity.app.setThread(null); // This should do nothing from a non-attached caller. assertFalse(mStack.navigateUpTo(secondActivity /* source record */, - firstActivity.intent /* destIntent */, 0 /* resultCode */, null /* resultData */)); + firstActivity.intent /* destIntent */, null /* destGrants */, + 0 /* resultCode */, null /* resultData */, null /* resultGrants */)); secondActivity.app.setThread(thread); assertTrue(mStack.navigateUpTo(secondActivity /* source record */, - firstActivity.intent /* destIntent */, 0 /* resultCode */, null /* resultData */)); + firstActivity.intent /* destIntent */, null /* destGrants */, + 0 /* resultCode */, null /* resultData */, null /* resultGrants */)); // The firstActivity uses default launch mode, so the activities between it and itself will // be finished. assertTrue(secondActivity.finishing); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index 27782f5b3683..ca4456b7b926 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -86,12 +86,12 @@ public class ActivityStartControllerTests extends ActivityTestsBase { wpc.setThread(mock(IApplicationThread.class)); mController.addPendingActivityLaunch( - new PendingActivityLaunch(activity, source, startFlags, stack, wpc)); + new PendingActivityLaunch(activity, source, startFlags, stack, wpc, null)); final boolean resume = random.nextBoolean(); mController.doPendingActivityLaunches(resume); verify(mStarter, times(1)).startResolvedActivity(eq(activity), eq(source), eq(null), - eq(null), eq(startFlags), eq(resume), eq(null), eq(null)); + eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 02d1f9b43e91..4a19684e5554 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -989,7 +989,7 @@ public class ActivityStarterTests extends ActivityTestsBase { .setUserId(10) .build(); - final int result = starter.recycleTask(task, null, null); + final int result = starter.recycleTask(task, null, null, null); assertThat(result == START_SUCCESS).isTrue(); assertThat(starter.mAddingToTask).isTrue(); } @@ -1068,7 +1068,8 @@ public class ActivityStarterTests extends ActivityTestsBase { /* doResume */true, /* options */null, /* inTask */null, - /* restrictedBgActivity */false); + /* restrictedBgActivity */false, + /* intentGrants */null); // Then verify(stack).ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); |