Allow background activity starts if realCallingUid is in
the foreground

Most notably adds support for:
- shortcuts (not PendingIntent-based, but realCallingUid is launcher,
which is foreground at the time of clicking)
- notifications, slices, actions and widgets (but only those that
are based on PendingIntent.getActivity() - trampolines are not yet
supported)

Note: this currently also allows PendingIntent-based starts for many
use cases where it's a persistent system process calling send(), but
we won't be allowing them anymore in forthcoming CLs (most notably
the AlarmManager use cases).

Bug: 110956953
Test: atest WmTests:ActivityStarterTests
Test: manual
Change-Id: I3c9de8cbe76bef5cc99d721536e19bb39b03405f
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index cba1044..c4421ba 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -738,7 +738,8 @@
         // not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
         // on START_ABORTED
         if (!abort) {
-            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, callerApp);
+            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid,
+                    callerApp);
         }
 
         // Merge the two options bundles, while realCallerOptions takes precedence.
@@ -886,7 +887,7 @@
     }
 
     private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
-            WindowProcessController callerApp) {
+            int realCallingUid, WindowProcessController callerApp) {
         if (mService.isBackgroundActivityStartsEnabled()) {
             return false;
         }
@@ -898,12 +899,12 @@
         if (callerApp != null && callerApp.hasForegroundActivities()) {
             return false;
         }
-        // don't abort if the callingUid's process is important enough
-        if (mService.getUidStateLocked(callingUid) <= ActivityManager.PROCESS_STATE_TOP) {
+        // don't abort if the callingUid is in the foreground
+        if (isUidForeground(callingUid)) {
             return false;
         }
-        // don't abort if the callingUid has any visible window
-        if (mService.mWindowManager.isAnyWindowVisibleForUid(callingUid)) {
+        // don't abort if the realCallingUid is in the foreground and callingUid isn't
+        if ((realCallingUid != callingUid) && isUidForeground(realCallingUid)) {
             return false;
         }
         // don't abort if the caller has the same uid as the recents component
@@ -920,6 +921,12 @@
         return true;
     }
 
+    /** Returns true if uid has a visible window or its process is in top or persistent state. */
+    private boolean isUidForeground(int uid) {
+        return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_TOP)
+            || mService.mWindowManager.isAnyWindowVisibleForUid(uid);
+    }
+
     private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
             Intent intent, WindowProcessController callerApp, ActivityRecord r,
             PendingIntentRecord originatingPendingIntent, boolean abortedStart) {
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 d78fbcd..f19e28d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -113,6 +113,7 @@
     private static final int FAKE_REAL_CALLING_UID = 667;
     private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
     private static final int UNIMPORTANT_UID = 12345;
+    private static final int UNIMPORTANT_UID2 = 12346;
 
     @Before
     public void setUp() throws Exception {
@@ -561,8 +562,10 @@
     public void testBackgroundActivityStartsAllowed_noStartsAborted() {
         doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
 
-        runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted",
-                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, false);
+        runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false);
     }
 
     /**
@@ -573,8 +576,11 @@
     public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
         doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
 
-        runAndVerifyBackgroundActivityStartsSubtest("disallowed_unsupportedUsecase_aborted",
-                true, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_unsupportedUsecase_aborted", true,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false);
     }
 
     /**
@@ -586,44 +592,77 @@
     public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
         doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
 
-        runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted",
-                false, Process.ROOT_UID, false, PROCESS_STATE_TOP + 1, false, false);
-        runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted",
-                false, Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1, false, false);
-        runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasVisibleWindow_notAborted",
-                false, UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1, false, false);
-        runAndVerifyBackgroundActivityStartsSubtest("disallowed_processStateTop_notAborted",
-                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP, false, false);
-        runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasForegroundActivities_notAborted",
-                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, true, false);
-        runAndVerifyBackgroundActivityStartsSubtest("disallowed_callerIsRecents_notAborted",
-                false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false, true);
+        runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
+                Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false);
+        runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
+                Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_callingUidHasVisibleWindow_notAborted", false,
+                UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_callingUidProcessStateTop_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
+                false, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_realCallingUidProcessStateTop_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
+                false, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_hasForegroundActivities_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                true, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_callerIsRecents_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, true);
     }
 
     private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
-            int testCallingUid, boolean hasVisibleWindow, int procState,
+            int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
+            int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
             boolean hasForegroundActivities, boolean callerIsRecents) {
         // window visibility
-        doReturn(hasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
-                testCallingUid);
+        doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
+                callingUid);
+        doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager)
+                .isAnyWindowVisibleForUid(realCallingUid);
         // process importance
-        doReturn(procState).when(mService).getUidStateLocked(testCallingUid);
+        doReturn(callingUidProcState).when(mService).getUidStateLocked(callingUid);
+        doReturn(realCallingUidProcState).when(mService).getUidStateLocked(realCallingUid);
         // foreground activities
         final IApplicationThread caller = mock(IApplicationThread.class);
         final ApplicationInfo ai = new ApplicationInfo();
-        ai.uid = testCallingUid;
+        ai.uid = callingUid;
         final WindowProcessController callerApp =
-                new WindowProcessController(mService, ai, null, testCallingUid, -1, null, null);
+                new WindowProcessController(mService, ai, null, callingUid, -1, null, null);
         callerApp.setHasForegroundActivities(hasForegroundActivities);
         doReturn(callerApp).when(mService).getProcessController(caller);
         // caller is recents
         RecentTasks recentTasks = mock(RecentTasks.class);
         mService.mStackSupervisor.setRecentTasks(recentTasks);
-        doReturn(callerIsRecents).when(recentTasks).isCallerRecents(testCallingUid);
+        doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
 
         final ActivityOptions options = spy(ActivityOptions.makeBasic());
-        ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK).setCaller(caller)
-                .setCallingUid(testCallingUid).setActivityOptions(new SafeActivityOptions(options));
+        ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
+                .setCaller(caller)
+                .setCallingUid(callingUid)
+                .setRealCallingUid(realCallingUid)
+                .setActivityOptions(new SafeActivityOptions(options));
 
         final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();