diff options
| author | 2018-12-10 17:51:42 +0000 | |
|---|---|---|
| committer | 2019-01-03 12:26:43 +0000 | |
| commit | ac116df5181b6bf82b501c2141f65633a935d9f0 (patch) | |
| tree | 1284a922cb217b9dfa325457e8828d68eda9e58e | |
| parent | 67b5e2ae1af0a3ce036d9cb8288e683a6ff86ccb (diff) | |
Block activity starts from background when realCallingUid is
a persistent system process and the start wasn't explicitly
whitelisted by the sender
Also, adds mechanism to temporary whitelist processes when
broadcast-based PendingIntent was whitelisted, so that
activities can be opened for the duration of the broadcast
being processed.
For now, all this is only wired for notifications.
Note: those whitelists are separate - only UI elements like
notifications will leverage both in order to support trampolines.
Other system-based PendingIntent senders should only use the
activity-based whitelist when they want an activity to be opened
from background.
Bug: 110956953
Test: atest WmTests:ActivityStarterTests
Test: manual with Play notifications that are known
for doing trampolines
Change-Id: Ibab91cdbe7afc0aed29d430dd41327272020925b
15 files changed, 199 insertions, 54 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index b42d53ad10f6..0b509169010c 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -73,6 +73,12 @@ public abstract class ActivityManagerInternal { IBinder whitelistToken, long duration); /** + * Allows for a {@link PendingIntent} to be whitelisted to start activities from background. + */ + public abstract void setPendingIntentAllowBgActivityStarts( + IIntentSender target, IBinder whitelistToken, int flags); + + /** * Allow DeviceIdleController to tell us about what apps are whitelisted. */ public abstract void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids); @@ -250,7 +256,7 @@ public abstract class ActivityManagerInternal { public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, - boolean sticky, int userId); + boolean sticky, int userId, boolean allowBackgroundActivityStarts); public abstract ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, boolean fgRequired, String callingPackage, int userId) throws TransactionTooLargeException; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1a5dd90b918a..5558e65813b0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3740,10 +3740,10 @@ public class ActivityManagerService extends IActivityManager.Stub intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0, null, null, permission.ACCESS_INSTANT_APPS, null, false, false, - resolvedUserId); + resolvedUserId, false); } else { broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0, - null, null, null, null, false, false, resolvedUserId); + null, null, null, null, false, false, resolvedUserId, false); } if (observer != null) { @@ -13992,7 +13992,7 @@ public class ActivityManagerService extends IActivityManager.Stub BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, null, null, -1, -1, false, null, null, OP_NONE, null, receivers, - null, 0, null, null, false, true, true, -1); + null, 0, null, null, false, true, true, -1, false); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } @@ -14231,6 +14231,18 @@ public class ActivityManagerService extends IActivityManager.Stub IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { + return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo, + resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered, + sticky, callingPid, callingUid, userId, false /* allowBackgroundActivityStarts */); + } + + @GuardedBy("this") + final int broadcastIntentLocked(ProcessRecord callerApp, + String callerPackage, Intent intent, String resolvedType, + IIntentReceiver resultTo, int resultCode, String resultData, + Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, + boolean ordered, boolean sticky, int callingPid, int callingUid, int userId, + boolean allowBackgroundActivityStarts) { intent = new Intent(intent); final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid); @@ -14731,7 +14743,8 @@ public class ActivityManagerService extends IActivityManager.Stub BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, appOp, brOptions, registeredReceivers, resultTo, - resultCode, resultData, resultExtras, ordered, sticky, false, userId); + resultCode, resultData, resultExtras, ordered, sticky, false, userId, + allowBackgroundActivityStarts); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r); final boolean replaced = replacePending && (queue.replaceParallelBroadcastLocked(r) != null); @@ -14827,7 +14840,8 @@ public class ActivityManagerService extends IActivityManager.Stub BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode, - resultData, resultExtras, ordered, sticky, false, userId); + resultData, resultExtras, ordered, sticky, false, userId, + allowBackgroundActivityStarts); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r + ": prev had " + queue.mOrderedBroadcasts.size()); @@ -14974,7 +14988,7 @@ public class ActivityManagerService extends IActivityManager.Stub Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky, - int userId) { + int userId, boolean allowBackgroundActivityStarts) { synchronized(this) { intent = verifyBroadcastLocked(intent); @@ -14984,7 +14998,7 @@ public class ActivityManagerService extends IActivityManager.Stub int res = broadcastIntentLocked(null, packageName, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, OP_NONE, bOptions, serialized, - sticky, -1, uid, userId); + sticky, -1, uid, userId, allowBackgroundActivityStarts); Binder.restoreCallingIdentity(origId); return res; } @@ -19040,6 +19054,19 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public void setPendingIntentAllowBgActivityStarts(IIntentSender target, + IBinder whitelistToken, int flags) { + if (!(target instanceof PendingIntentRecord)) { + Slog.w(TAG, "setPendingIntentAllowBgActivityStarts():" + + " not a PendingIntentRecord: " + target); + return; + } + synchronized (ActivityManagerService.this) { + ((PendingIntentRecord) target).setAllowBgActivityStarts(whitelistToken, flags); + } + } + + @Override public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) { synchronized (ActivityManagerService.this) { mDeviceIdleWhitelist = allAppids; @@ -19426,11 +19453,12 @@ public class ActivityManagerService extends IActivityManager.Stub public int broadcastIntentInPackage(String packageName, int uid, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, - boolean sticky, int userId) { + boolean sticky, int userId, boolean allowBackgroundActivityStarts) { synchronized (ActivityManagerService.this) { return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, - requiredPermission, bOptions, serialized, sticky, userId); + requiredPermission, bOptions, serialized, sticky, userId, + allowBackgroundActivityStarts); } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index c290fbe09864..65aacdcb73e0 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -287,6 +287,9 @@ public final class BroadcastQueue { r.curApp = app; app.curReceivers.add(r); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); + if (r.allowBackgroundActivityStarts) { + app.addAllowBackgroundActivityStartsToken(r); + } mService.mProcessList.updateLruProcessLocked(app, false, null); if (!skipOomAdj) { mService.updateOomAdjLocked(); @@ -415,6 +418,9 @@ public final class BroadcastQueue { if (state == BroadcastRecord.IDLE) { Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE"); } + if (r.allowBackgroundActivityStarts) { + r.curApp.removeAllowBackgroundActivityStartsToken(r); + } // If we're abandoning this broadcast before any receivers were actually spun up, // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply. if (r.nextReceiver > 0) { diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 9b7dc44e5a73..9e799f6f14f3 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -81,6 +81,10 @@ final class BroadcastRecord extends Binder { int manifestSkipCount; // number of manifest receivers skipped. BroadcastQueue queue; // the outbound queue handling this broadcast + // if set to true, app's process will be temporarily whitelisted to start activities + // from background for the duration of the broadcast dispatch + final boolean allowBackgroundActivityStarts; + static final int IDLE = 0; static final int APP_RECEIVE = 1; static final int CALL_IN_RECEIVE = 2; @@ -223,7 +227,8 @@ final class BroadcastRecord extends Binder { int _callingPid, int _callingUid, boolean _callerInstantApp, String _resolvedType, String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras, - boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId) { + boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId, + boolean _allowBackgroundActivityStarts) { if (_intent == null) { throw new NullPointerException("Can't construct with a null intent"); } @@ -252,6 +257,7 @@ final class BroadcastRecord extends Binder { userId = _userId; nextReceiver = 0; state = IDLE; + allowBackgroundActivityStarts = _allowBackgroundActivityStarts; } /** @@ -295,6 +301,7 @@ final class BroadcastRecord extends Binder { manifestCount = from.manifestCount; manifestSkipCount = from.manifestSkipCount; queue = from.queue; + allowBackgroundActivityStarts = from.allowBackgroundActivityStarts; } public BroadcastRecord maybeStripForHistory() { diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 447243b542ea..b675d9d4f9cf 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -34,6 +34,7 @@ import android.os.RemoteException; import android.os.TransactionTooLargeException; import android.os.UserHandle; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Slog; import android.util.TimeUtils; @@ -48,6 +49,9 @@ import java.util.Objects; public final class PendingIntentRecord extends IIntentSender.Stub { private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; + public static final int FLAG_ACTIVITY_SENDER = 1 << 0; + public static final int FLAG_BROADCAST_SENDER = 1 << 1; + final PendingIntentController controller; final Key key; final int uid; @@ -56,6 +60,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub { boolean canceled = false; private ArrayMap<IBinder, Long> whitelistDuration; private RemoteCallbackList<IResultReceiver> mCancelCallbacks; + private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>(); + private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>(); String stringName; String lastTagPrefix; @@ -214,6 +220,16 @@ public final class PendingIntentRecord extends IIntentSender.Stub { this.stringName = null; } + void setAllowBgActivityStarts(IBinder token, int flags) { + if (token == null) return; + if ((flags & FLAG_ACTIVITY_SENDER) != 0) { + mAllowBgActivityStartsForActivitySender.add(token); + } + if ((flags & FLAG_BROADCAST_SENDER) != 0) { + mAllowBgActivityStartsForBroadcastSender.add(token); + } + } + public void registerCancelListenerLocked(IResultReceiver receiver) { if (mCancelCallbacks == null) { mCancelCallbacks = new RemoteCallbackList<>(); @@ -370,14 +386,16 @@ public final class PendingIntentRecord extends IIntentSender.Stub { res = controller.mAtmInternal.startActivitiesInPackage( uid, key.packageName, allIntents, allResolvedTypes, resultTo, mergedOptions, userId, false /* validateIncomingUser */, - this /* originatingPendingIntent */); + this /* originatingPendingIntent */, + mAllowBgActivityStartsForActivitySender.contains(whitelistToken)); } else { res = controller.mAtmInternal.startActivityInPackage( uid, callingPid, callingUid, key.packageName, finalIntent, resolvedType, resultTo, resultWho, requestCode, 0, mergedOptions, userId, null, "PendingIntentRecord", false /* validateIncomingUser */, - this /* originatingPendingIntent */); + this /* originatingPendingIntent */, + mAllowBgActivityStartsForActivitySender.contains(whitelistToken)); } } catch (RuntimeException e) { Slog.w(TAG, "Unable to send startActivity intent", e); @@ -394,7 +412,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub { int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName, uid, finalIntent, resolvedType, finishedReceiver, code, null, null, requiredPermission, options, (finishedReceiver != null), - false, userId); + false, userId, + mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)); if (sent == ActivityManager.BROADCAST_SUCCESS) { sendFinish = false; } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index c15b7c7d82c2..6f0a562eb819 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -249,6 +249,9 @@ final class ProcessRecord implements WindowProcessListener { final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>(); // All ContentProviderRecord process is using final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>(); + // A set of tokens that currently contribute to this process being temporarily whitelisted + // to start activities even if it's not in the foreground + final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>(); String isolatedEntryPoint; // Class to run on start if this is a special isolated process. String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main(). @@ -1135,6 +1138,17 @@ final class ProcessRecord implements WindowProcessListener { return mUsingWrapper; } + void addAllowBackgroundActivityStartsToken(Binder entity) { + mAllowBackgroundActivityStartsTokens.add(entity); + mWindowProcessController.setAllowBackgroundActivityStarts(true); + } + + void removeAllowBackgroundActivityStartsToken(Binder entity) { + mAllowBackgroundActivityStartsTokens.remove(entity); + mWindowProcessController.setAllowBackgroundActivityStarts( + !mAllowBackgroundActivityStartsTokens.isEmpty()); + } + void setActiveInstrumentation(ActiveInstrumentation instr) { mInstr = instr; mWindowProcessController.setInstrumenting(instr != null); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e2cb75e96882..708f64bd5482 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -75,6 +75,8 @@ import static android.service.notification.NotificationListenerService.TRIM_FULL import static android.service.notification.NotificationListenerService.TRIM_LIGHT; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; +import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; import static com.android.server.utils.PriorityDump.PRIORITY_ARG; import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL; import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL; @@ -4420,6 +4422,8 @@ public class NotificationManagerService extends SystemService { if (pendingIntent != null) { am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), WHITELIST_TOKEN, duration); + am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(), + WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER)); } } } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index f58b83d682f6..d5286b9ae87c 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -2657,7 +2657,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { return mService.getActivityStartController().startActivityInPackage( task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null, null, 0, 0, options, userId, task, "startActivityFromRecents", - false /* validateIncomingUser */, null /* originatingPendingIntent */); + false /* validateIncomingUser */, null /* originatingPendingIntent */, + false /* allowBackgroundActivityStart */); } finally { if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) { // If we are launching the task in the docked stack, put it into resizing mode so diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index b4d5d9f6e5cd..08596836ed4d 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -258,7 +258,7 @@ public class ActivityStartController { String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, SafeActivityOptions options, int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, - PendingIntentRecord originatingPendingIntent) { + PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid, reason); @@ -278,6 +278,7 @@ public class ActivityStartController { .setMayWait(userId) .setInTask(inTask) .setOriginatingPendingIntent(originatingPendingIntent) + .setAllowBackgroundActivityStart(allowBackgroundActivityStart) .execute(); } @@ -294,7 +295,8 @@ public class ActivityStartController { */ final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, - boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) { + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, + boolean allowBackgroundActivityStart) { final String reason = "startActivityInPackage"; @@ -303,12 +305,13 @@ public class ActivityStartController { // TODO: Switch to user app stacks here. return startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, options, - userId, reason, originatingPendingIntent); + userId, reason, originatingPendingIntent, allowBackgroundActivityStart); } int startActivities(IApplicationThread caller, int callingUid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, - int userId, String reason, PendingIntentRecord originatingPendingIntent) { + int userId, String reason, PendingIntentRecord originatingPendingIntent, + boolean allowBackgroundActivityStart) { if (intents == null) { throw new NullPointerException("intents is null"); } @@ -387,6 +390,7 @@ public class ActivityStartController { // top one as otherwise an activity below might consume it. .setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/) .setOriginatingPendingIntent(originatingPendingIntent) + .setAllowBackgroundActivityStart(allowBackgroundActivityStart) .execute(); if (res < 0) { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 36701ea599dc..b100ecdb0e73 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -323,6 +323,7 @@ class ActivityStarter { WaitResult waitResult; int filterCallingUid; PendingIntentRecord originatingPendingIntent; + boolean allowBackgroundActivityStart; /** * If set to {@code true}, allows this activity start to look into @@ -380,6 +381,7 @@ class ActivityStarter { allowPendingRemoteAnimationRegistryLookup = true; filterCallingUid = UserHandle.USER_NULL; originatingPendingIntent = null; + allowBackgroundActivityStart = false; } /** @@ -419,6 +421,7 @@ class ActivityStarter { = request.allowPendingRemoteAnimationRegistryLookup; filterCallingUid = request.filterCallingUid; originatingPendingIntent = request.originatingPendingIntent; + allowBackgroundActivityStart = request.allowBackgroundActivityStart; } } @@ -504,7 +507,7 @@ class ActivityStarter { mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup, - mRequest.originatingPendingIntent); + mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart); } else { return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo, @@ -515,7 +518,7 @@ class ActivityStarter { mRequest.ignoreTargetSecurity, mRequest.componentSpecified, mRequest.outActivity, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup, - mRequest.originatingPendingIntent); + mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart); } } finally { onExecutionComplete(); @@ -548,7 +551,7 @@ class ActivityStarter { SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, TaskRecord inTask, String reason, boolean allowPendingRemoteAnimationRegistryLookup, - PendingIntentRecord originatingPendingIntent) { + PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { if (TextUtils.isEmpty(reason)) { throw new IllegalArgumentException("Need to specify a reason."); @@ -561,7 +564,8 @@ class ActivityStarter { aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord, - inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent); + inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent, + allowBackgroundActivityStart); if (outActivity != null) { // mLastStartActivityRecord[0] is set in the call to startActivity above. @@ -592,7 +596,7 @@ class ActivityStarter { SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup, - PendingIntentRecord originatingPendingIntent) { + PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { int err = ActivityManager.START_SUCCESS; // Pull the optional Ephemeral Installer-only bundle out of the options early. final Bundle verificationBundle @@ -742,7 +746,7 @@ class ActivityStarter { // on START_ABORTED if (!abort) { abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid, - callerApp); + callerApp, originatingPendingIntent, allowBackgroundActivityStart); } // Merge the two options bundles, while realCallerOptions takes precedence. @@ -890,7 +894,8 @@ class ActivityStarter { } private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage, - int realCallingUid, WindowProcessController callerApp) { + int realCallingUid, WindowProcessController callerApp, + PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { if (mService.isBackgroundActivityStartsEnabled()) { return false; } @@ -902,12 +907,25 @@ class ActivityStarter { if (callerApp != null && callerApp.hasForegroundActivities()) { return false; } - // don't abort if the callingUid is in the foreground - if (isUidForeground(callingUid)) { + // don't abort if the callingUid is in the foreground or is a persistent system process + if (isUidForeground(callingUid) || isUidPersistentSystemProcess(callingUid)) { return false; } - // don't abort if the realCallingUid is in the foreground and callingUid isn't - if ((realCallingUid != callingUid) && isUidForeground(realCallingUid)) { + // take realCallingUid into consideration + if (realCallingUid != callingUid) { + // don't abort if the realCallingUid is in the foreground and callingUid isn't + if (isUidForeground(realCallingUid)) { + return false; + } + // if the realCallingUid is a persistent system process, abort if the IntentSender + // wasn't whitelisted to start an activity + if (isUidPersistentSystemProcess(realCallingUid) && (originatingPendingIntent != null) + && allowBackgroundActivityStart) { + return false; + } + } + // don't abort if the caller is currently temporarily whitelisted + if (callerApp != null && callerApp.areBackgroundActivityStartsAllowed()) { return false; } // don't abort if the caller has the same uid as the recents component @@ -924,12 +942,17 @@ class ActivityStarter { return true; } - /** Returns true if uid has a visible window or its process is in top or persistent state. */ + /** Returns true if uid has a visible window or its process is in a top state. */ private boolean isUidForeground(int uid) { - return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_TOP) + return (mService.getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP) || mService.mWindowManager.isAnyWindowVisibleForUid(uid); } + /** Returns true if uid is in a persistent state. */ + private boolean isUidPersistentSystemProcess(int uid) { + return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI); + } + private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid, Intent intent, WindowProcessController callerApp, ActivityRecord r, PendingIntentRecord originatingPendingIntent, boolean abortedStart) { @@ -1049,7 +1072,7 @@ class ActivityStarter { Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity, int userId, TaskRecord inTask, String reason, boolean allowPendingRemoteAnimationRegistryLookup, - PendingIntentRecord originatingPendingIntent) { + PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -1195,7 +1218,8 @@ class ActivityStarter { voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason, - allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent); + allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent, + allowBackgroundActivityStart); Binder.restoreCallingIdentity(origId); @@ -2731,6 +2755,11 @@ class ActivityStarter { return this; } + ActivityStarter setAllowBackgroundActivityStart(boolean allowBackgroundActivityStart) { + mRequest.allowBackgroundActivityStart = allowBackgroundActivityStart; + return this; + } + void dump(PrintWriter pw, String prefix) { prefix = prefix + " "; pw.print(prefix); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 0fc890a39fed..0f286ce30ccd 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -197,16 +197,19 @@ public abstract class ActivityTaskManagerInternal { * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID. * @param originatingPendingIntent PendingIntentRecord that originated this activity start or * null if not originated by PendingIntent + * @param allowBackgroundActivityStart Whether the background activity start should be allowed + * from originatingPendingIntent */ public abstract int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, - boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent); + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, + boolean allowBackgroundActivityStart); public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, SafeActivityOptions options, int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, - PendingIntentRecord originatingPendingIntent); + PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart); /** * Start activity {@code intent} without calling user-id check. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index c4be1ba53706..a669ace208d2 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -960,7 +960,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // TODO: Switch to user app stacks here. return getActivityStartController().startActivities(caller, -1, callingPackage, intents, resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, reason, - null /* originatingPendingIntent */); + null /* originatingPendingIntent */, false /* allowBackgroundActivityStart */); } @Override @@ -5787,18 +5787,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { packageUid, packageName, intents, resolvedTypes, null /* resultTo */, SafeActivityOptions.fromBundle(bOptions), userId, - false /* validateIncomingUser */, null /* originatingPendingIntent */); + false /* validateIncomingUser */, null /* originatingPendingIntent */, + false /* allowBackgroundActivityStart */); } } @Override public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, - boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) { + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, + boolean allowBackgroundActivityStart) { synchronized (mGlobalLock) { return getActivityStartController().startActivitiesInPackage(uid, callingPackage, intents, resolvedTypes, resultTo, options, userId, validateIncomingUser, - originatingPendingIntent); + originatingPendingIntent, allowBackgroundActivityStart); } } @@ -5807,12 +5809,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, SafeActivityOptions options, int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, - PendingIntentRecord originatingPendingIntent) { + PendingIntentRecord originatingPendingIntent, + boolean allowBackgroundActivityStart) { synchronized (mGlobalLock) { return getActivityStartController().startActivityInPackage(uid, realCallingPid, realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, options, userId, inTask, reason, - validateIncomingUser, originatingPendingIntent); + validateIncomingUser, originatingPendingIntent, + allowBackgroundActivityStart); } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index f7f7528c5234..c38a974ac774 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -141,6 +141,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private volatile boolean mPerceptible; // Set to true when process was launched with a wrapper attached private volatile boolean mUsingWrapper; + // Set to true if this process is currently temporarily whitelisted to start activities even if + // it's not in the foreground + private volatile boolean mAllowBackgroundActivityStarts; // Thread currently set for VR scheduling int mVrThreadTid; @@ -343,6 +346,14 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return mUsingWrapper; } + public void setAllowBackgroundActivityStarts(boolean allowBackgroundActivityStarts) { + mAllowBackgroundActivityStarts = allowBackgroundActivityStarts; + } + + public boolean areBackgroundActivityStartsAllowed() { + return mAllowBackgroundActivityStarts; + } + public void setInstrumenting(boolean instrumenting) { mInstrumenting = instrumenting; } diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java index 0889265dd663..d4bb6369c710 100644 --- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java +++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java @@ -193,6 +193,7 @@ public class BroadcastRecordTest { false /* serialized */, false /* sticky */, false /* initialSticky */, - userId); + userId, + false /* allowBackgroundActivityStarts */); } } 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 61e968d6da00..7a6b2b50d1e1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -565,7 +565,7 @@ public class ActivityStarterTests extends ActivityTestsBase { runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false); + false, false, false); } /** @@ -580,7 +580,7 @@ public class ActivityStarterTests extends ActivityTestsBase { "disallowed_unsupportedUsecase_aborted", true, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false); + false, false, false); } /** @@ -595,47 +595,53 @@ public class ActivityStarterTests extends ActivityTestsBase { runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false, Process.ROOT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false); + false, false, false); runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false, Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false); + false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callingUidHasVisibleWindow_notAborted", false, UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false); + false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callingUidProcessStateTop_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false); + false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_realCallingUidHasVisibleWindow_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1, - false, false); + false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_realCallingUidProcessStateTop_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, - false, false); + false, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_hasForegroundActivities_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - true, false); + true, false, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callerIsRecents_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, true); + false, true, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_callerIsWhitelisted_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + false, false, true); } private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, - boolean hasForegroundActivities, boolean callerIsRecents) { + boolean hasForegroundActivities, boolean callerIsRecents, + boolean callerIsTempWhitelisted) { // window visibility doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid( callingUid); @@ -656,6 +662,8 @@ public class ActivityStarterTests extends ActivityTestsBase { RecentTasks recentTasks = mock(RecentTasks.class); mService.mStackSupervisor.setRecentTasks(recentTasks); doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid); + // caller is temp whitelisted + callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted); final ActivityOptions options = spy(ActivityOptions.makeBasic()); ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK) |