Fix cross-user background activity starts.
This fixes some issues with checking background activity starts when
there are multiple users:
1. System server can run in other users, and we need to take this into
account when checking for Process.SYTEM_UID.
2. Starting an activity via cross-profile intent uses
startActivityAsCaller. This will generally fail our checks (because the
app we are pretending to be is not foreground) but it should be
allowed - when we use this call the system server definitely wants the
activity to be shown, and there are sufficient permission checks in
place to prevent abuse.
Bug: 130622120
Test: CTS Verifier tests no longer get blocked activity starts.
Test: atest BackgroundActivityLaunchTest
Test: atest RootWindowContainerTests
Test: atest WmTests:ActivityStarterTests
Test: atest CtsWindowManagerDeviceTestCases:ActivityStarterTests
Test: atest CtsAppTestCases:.ServiceTest
Change-Id: Id05a2cb089ac99b15cff8a3cd311ee043f13c8e1
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e7e34bb..2846b38 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -942,8 +942,9 @@
WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart, Intent intent) {
// don't abort for the most important UIDs
- if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID
- || callingUid == Process.NFC_UID) {
+ final int callingAppId = UserHandle.getAppId(callingUid);
+ if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
+ || callingAppId == Process.NFC_UID) {
return false;
}
// don't abort if the callingUid has a visible window or is a persistent system process
@@ -953,8 +954,8 @@
final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
|| callingUidProcState == ActivityManager.PROCESS_STATE_TOP
|| callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
- final boolean isCallingUidPersistentSystemProcess = (callingUid == Process.SYSTEM_UID)
- || callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+ final boolean isCallingUidPersistentSystemProcess =
+ callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) {
return false;
}
@@ -969,14 +970,15 @@
? isCallingUidForeground
: realCallingUidHasAnyVisibleWindow
|| realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
+ final int realCallingAppId = UserHandle.getAppId(realCallingUid);
final boolean isRealCallingUidPersistentSystemProcess = (callingUid == realCallingUid)
? isCallingUidPersistentSystemProcess
- : (realCallingUid == Process.SYSTEM_UID)
+ : (realCallingAppId == Process.SYSTEM_UID)
|| realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
if (realCallingUid != callingUid) {
// don't abort if the realCallingUid has a visible window, unless realCallingUid is
// SYSTEM_UID, in which case it start needs to be explicitly whitelisted
- if (realCallingUidHasAnyVisibleWindow && realCallingUid != Process.SYSTEM_UID) {
+ if (realCallingUidHasAnyVisibleWindow && realCallingAppId != Process.SYSTEM_UID) {
return false;
}
// if the realCallingUid is a persistent system process, abort if the IntentSender
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b234bc6..a8b56d3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1375,6 +1375,9 @@
.setMayWait(userId)
.setIgnoreTargetSecurity(ignoreTargetSecurity)
.setFilterCallingUid(isResolver ? 0 /* system */ : targetUid)
+ // The target may well be in the background, which would normally prevent it
+ // from starting an activity. Here we definitely want the start to succeed.
+ .setAllowBackgroundActivityStart(true)
.execute();
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.