Extend temporary whitelisting mechanism to support trampolines
from PendingIntents for broadcasts and services if PI.send()
caller is in the foreground
Bug: 122886181
Bug: 110956953
Test: atest WmTests:ActivityStarterTests
Test: manual, with Chrome custom tabs
Change-Id: I5f9ee41a6fdbca51ad356825c3ede151b98c77e8
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 55cca95..0b27a8a 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -379,6 +379,10 @@
if (userId == UserHandle.USER_CURRENT) {
userId = controller.mUserController.getCurrentOrTargetUserId();
}
+ // temporarily allow receivers and services to open activities from background if the
+ // PendingIntent.send() caller was foreground at the time of sendInner() call
+ final boolean allowTrampoline = uid != callingUid
+ && controller.mAtmInternal.isUidForeground(callingUid);
switch (key.type) {
case ActivityManager.INTENT_SENDER_ACTIVITY:
@@ -419,7 +423,8 @@
uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
requiredPermission, options, (finishedReceiver != null),
false, userId,
- mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken));
+ mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
+ || allowTrampoline);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
}
@@ -433,7 +438,8 @@
controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
key.packageName, userId,
- mAllowBgActivityStartsForServiceSender.contains(whitelistToken));
+ mAllowBgActivityStartsForServiceSender.contains(whitelistToken)
+ || allowTrampoline);
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startService intent", e);
} catch (TransactionTooLargeException e) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 865ffbd..0652182 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -924,14 +924,15 @@
return false;
}
// don't abort if the callingUid is in the foreground or is a persistent system process
- final boolean isCallingUidForeground = isUidForeground(callingUid);
+ final boolean isCallingUidForeground = mService.isUidForeground(callingUid);
final boolean isCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
callingUid);
if (isCallingUidForeground || isCallingUidPersistentSystemProcess) {
return false;
}
// take realCallingUid into consideration
- final boolean isRealCallingUidForeground = isUidForeground(realCallingUid);
+ final boolean isRealCallingUidForeground = mService.isUidForeground(
+ realCallingUid);
final boolean isRealCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
realCallingUid);
if (realCallingUid != callingUid) {
@@ -976,12 +977,6 @@
return true;
}
- /** 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)
- || mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
- }
-
/** Returns true if uid is in a persistent state. */
private boolean isUidPersistentSystemProcess(int uid) {
return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 67b00b2..1a5e6a1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -489,4 +489,7 @@
*/
public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId,
boolean reducedResolution);
+
+ /** Returns true if uid has a visible window or its process is in a top state. */
+ public abstract boolean isUidForeground(int uid);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ea6f4cc..e5a66cb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5632,6 +5632,11 @@
return mActiveUids.get(uid, PROCESS_STATE_NONEXISTENT);
}
+ boolean isUidForeground(int uid) {
+ return (getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
+ || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
+ }
+
/**
* @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
* the whitelist
@@ -7041,5 +7046,12 @@
return ActivityTaskManagerService.this.getTaskSnapshot(taskId, reducedResolution);
}
}
+
+ @Override
+ public boolean isUidForeground(int uid) {
+ synchronized (mGlobalLock) {
+ return ActivityTaskManagerService.this.isUidForeground(uid);
+ }
+ }
}
}