Don't allow PI-based starts and trampolines when sender
is SYSTEM_UID and it happens to pass foregroundness check
at the time of sending

It could lead to abuses like directing the user to Settings app
and then giving a PI through any API, so that app could open
activity/trampoline due to Settings app (SYSTEM_UID) being fg.

PI-based starts where sender is SYSTEM_UID will no longer be
supported based on foregroundness check. Any such starts need
to now be explicitly whitelisted (see b/124858756).

Also, ignore windows of type TYPE_APPLICATION_STARTING in
isAnyNonToastWindowVisibleForUid() check.

Bug: 129563343
Test: atest WmTests:ActivityStarterTests
Test: atest BackgroundActivityLaunchTest
Test: atest CtsActivityManagerDeviceTestCases:ActivityStarterTests
Test: atest WmTests:RootWindowContainerTests
Change-Id: I563f71f0b1c7922d8c675d2e4feed909f43446be
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index a08c829..588e05d 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -29,6 +29,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.TransactionTooLargeException;
@@ -380,8 +381,9 @@
                 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
+            // PendingIntent.send() caller was foreground at the time of sendInner() call, unless
+            // caller is SYSTEM_UID
+            final boolean allowTrampoline = uid != callingUid && callingUid != Process.SYSTEM_UID
                     && controller.mAtmInternal.isUidForeground(callingUid);
 
             // note: we on purpose don't pass in the information about the PendingIntent's creator,
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ea9477f..4ef8753 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -971,8 +971,9 @@
                 : (realCallingUid == Process.SYSTEM_UID)
                         || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
         if (realCallingUid != callingUid) {
-            // don't abort if the realCallingUid has a visible window
-            if (realCallingUidHasAnyVisibleWindow) {
+            // 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) {
                 return false;
             }
             // if the realCallingUid is a persistent system process, abort if the IntentSender
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f9fd541..9f42324 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -312,11 +313,12 @@
 
     /**
      * Returns true if the callingUid has any non-toast window currently visible to the user.
+     * Also ignores TYPE_APPLICATION_STARTING, since those windows don't belong to apps.
      */
     boolean isAnyNonToastWindowVisibleForUid(int callingUid) {
         return forAllWindows(w ->
                         w.getOwningUid() == callingUid && w.mAttrs.type != TYPE_TOAST
-                        && w.isVisibleNow(),
+                        && w.mAttrs.type != TYPE_APPLICATION_STARTING && w.isVisibleNow(),
                 true /* traverseTopToBottom */);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 263f650..f51ce13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
@@ -44,14 +45,18 @@
     private static final int FAKE_CALLING_UID = 667;
 
     @Test
-    public void testIsAnyNonToastWindowVisibleForUid_oneToastOneNonToastBothVisible() {
+    public void testIsAnyNonToastWindowVisibleForUid_oneToastOneAppStartOneNonToastBothVisible() {
         final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID);
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID);
+        final WindowState appStart = createWindow(null, TYPE_APPLICATION_STARTING, "appStarting",
+                FAKE_CALLING_UID);
         toastyToast.mHasSurface = true;
         app.mHasSurface = true;
+        appStart.mHasSurface = true;
 
         assertTrue(toastyToast.isVisibleNow());
         assertTrue(app.isVisibleNow());
+        assertTrue(appStart.isVisibleNow());
         assertTrue(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
     }
 
@@ -65,6 +70,16 @@
     }
 
     @Test
+    public void testIsAnyNonToastWindowVisibleForUid_onlyAppStartingVisible() {
+        final WindowState appStart = createWindow(null, TYPE_APPLICATION_STARTING, "appStarting",
+                FAKE_CALLING_UID);
+        appStart.mHasSurface = true;
+
+        assertTrue(appStart.isVisibleNow());
+        assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
+    }
+
+    @Test
     public void testIsAnyNonToastWindowVisibleForUid_aFewNonToastButNoneVisible() {
         final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar", FAKE_CALLING_UID);
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID);