Merge "Don’t bring App to FG if only creator is allowed to do BAL(1/2)" into main
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 009b8e0..5e0a449 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -133,6 +133,7 @@
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
 import com.android.server.wm.BackgroundActivityStartController.BalCode;
+import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
 import com.android.server.wm.LaunchParamsController.LaunchParams;
 import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
 
@@ -1090,14 +1091,14 @@
         ActivityOptions checkedOptions = options != null
                 ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
 
-        @BalCode int balCode = BAL_ALLOW_DEFAULT;
+        final BalVerdict balVerdict;
         if (!abort) {
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
                         "shouldAbortBackgroundActivityStart");
                 BackgroundActivityStartController balController =
                         mSupervisor.getBackgroundActivityLaunchController();
-                BackgroundActivityStartController.BalVerdict balVerdict =
+                balVerdict =
                         balController.checkBackgroundActivityStart(
                             callingUid,
                             callingPid,
@@ -1109,13 +1110,13 @@
                             request.forcedBalByPiSender,
                             intent,
                             checkedOptions);
-                balCode = balVerdict.getCode();
-                request.logMessage.append(" (").append(
-                                BackgroundActivityStartController.balCodeToString(balCode))
-                        .append(")");
+                request.logMessage.append(" (").append(balVerdict).append(")");
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             }
+        } else {
+            // Sets ALLOW_BY_DEFAULT as default value as the activity launch will be aborted anyway.
+            balVerdict = BalVerdict.ALLOW_BY_DEFAULT;
         }
 
         if (request.allowPendingRemoteAnimationRegistryLookup) {
@@ -1293,13 +1294,13 @@
         WindowProcessController homeProcess = mService.mHomeProcess;
         boolean isHomeProcess = homeProcess != null
                 && aInfo.applicationInfo.uid == homeProcess.mUid;
-        if (balCode != BAL_BLOCK && !isHomeProcess) {
+        if (balVerdict.allows() && !isHomeProcess) {
             mService.resumeAppSwitches();
         }
 
         mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                 request.voiceInteractor, startFlags, checkedOptions,
-                inTask, inTaskFragment, balCode, intentGrants, realCallingUid);
+                inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid);
 
         if (request.outActivity != null) {
             request.outActivity[0] = mLastStartActivityRecord;
@@ -1449,7 +1450,8 @@
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, ActivityOptions options, Task inTask,
-            TaskFragment inTaskFragment, @BalCode int balCode,
+            TaskFragment inTaskFragment,
+            BalVerdict balVerdict,
             NeededUriGrants intentGrants, int realCallingUid) {
         int result = START_CANCELED;
         final Task startedActivityRootTask;
@@ -1468,7 +1470,7 @@
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
                 result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
-                        startFlags, options, inTask, inTaskFragment, balCode,
+                        startFlags, options, inTask, inTaskFragment, balVerdict,
                         intentGrants, realCallingUid);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -1615,10 +1617,10 @@
     int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, ActivityOptions options, Task inTask,
-            TaskFragment inTaskFragment, @BalCode int balCode,
+            TaskFragment inTaskFragment, BalVerdict balVerdict,
             NeededUriGrants intentGrants, int realCallingUid) {
         setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord,
-                voiceSession, voiceInteractor, balCode, realCallingUid);
+                voiceSession, voiceInteractor, balVerdict.getCode(), realCallingUid);
 
         computeLaunchingTaskFlags();
         mIntent.setFlags(mLaunchFlags);
@@ -1696,7 +1698,8 @@
             }
             recordTransientLaunchIfNeeded(targetTaskTop);
             // Recycle the target task for this launch.
-            startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
+            startResult =
+                    recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants, balVerdict);
             if (startResult != START_SUCCESS) {
                 return startResult;
             }
@@ -1730,6 +1733,7 @@
         recordTransientLaunchIfNeeded(mLastStartActivityRecord);
 
         if (!mAvoidMoveToFront && mDoResume) {
+            logOnlyCreatorAllowsBAL(balVerdict, realCallingUid, newTask);
             mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
             if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.isDreaming()
                     && !dreamStopping) {
@@ -1800,6 +1804,7 @@
                 // now update the focused root-task accordingly.
                 if (!mAvoidMoveToFront && mTargetRootTask.isTopActivityFocusable()
                         && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
+                    logOnlyCreatorAllowsBAL(balVerdict, realCallingUid, newTask);
                     mTargetRootTask.moveToFront("startActivityInner");
                 }
                 mRootWindowContainer.resumeFocusedTasksTopActivities(
@@ -1817,7 +1822,7 @@
         // Note that mStartActivity and source should be in the same Task at this point.
         if (mOptions != null && mOptions.isLaunchIntoPip()
                 && sourceRecord != null && sourceRecord.getTask() == mStartActivity.getTask()
-                && balCode != BAL_BLOCK) {
+                && balVerdict.allows()) {
             mRootWindowContainer.moveActivityToPinnedRootTask(mStartActivity,
                     sourceRecord, "launch-into-pip");
         }
@@ -1828,6 +1833,24 @@
         return START_SUCCESS;
     }
 
+    private void logOnlyCreatorAllowsBAL(BalVerdict balVerdict,
+            int realCallingUid, boolean newTask) {
+        // TODO (b/296478675) eventually, we will prevent such case from happening
+        // and probably also log that a BAL is prevented by android V.
+        if (!newTask && balVerdict.onlyCreatorAllows()) {
+            String realCallingPackage =
+                    mService.mContext.getPackageManager().getNameForUid(realCallingUid);
+            if (realCallingPackage == null) {
+                realCallingPackage = "uid=" + realCallingUid;
+            }
+            Slog.wtf(TAG, "A background app is brought to the foreground due to a "
+                    + "PendingIntent. However, only the creator of the PendingIntent allows BAL, "
+                    + "while the sender does not allow BAL. realCallingPackage: "
+                    + realCallingPackage + "; callingPackage: " + mRequest.callingPackage
+                    + "; mTargetRootTask:" + mTargetRootTask);
+        }
+    }
+
     private void recordTransientLaunchIfNeeded(ActivityRecord r) {
         if (r == null || !mTransientLaunch) return;
         final TransitionController controller = r.mTransitionController;
@@ -1995,7 +2018,7 @@
      */
     @VisibleForTesting
     int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask,
-            NeededUriGrants intentGrants) {
+            NeededUriGrants intentGrants, BalVerdict balVerdict) {
         // Should not recycle task which is from a different user, just adding the starting
         // activity to the task.
         if (targetTask.mUserId != mStartActivity.mUserId) {
@@ -2024,7 +2047,7 @@
         mRootWindowContainer.startPowerModeLaunchIfNeeded(false /* forceSend */,
                 targetTaskTop);
 
-        setTargetRootTaskIfNeeded(targetTaskTop);
+        setTargetRootTaskIfNeeded(targetTaskTop, balVerdict);
 
         // When there is a reused activity and the current result is a trampoline activity,
         // set the reused activity as the result.
@@ -2040,6 +2063,7 @@
             if (!mMovedToFront && mDoResume) {
                 ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetRootTask,
                         targetTaskTop);
+                logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
                 mTargetRootTask.moveToFront("intentActivityFound");
             }
             resumeTargetRootTaskIfNeeded();
@@ -2068,6 +2092,7 @@
             targetTaskTop.showStartingWindow(true /* taskSwitch */);
         } else if (mDoResume) {
             // Make sure the root task and its belonging display are moved to topmost.
+            logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
             mTargetRootTask.moveToFront("intentActivityFound");
         }
         // We didn't do anything...  but it was needed (a.k.a., client don't use that intent!)
@@ -2663,7 +2688,7 @@
      * @param intentActivity Existing matching activity.
      * @return {@link ActivityRecord} brought to front.
      */
-    private void setTargetRootTaskIfNeeded(ActivityRecord intentActivity) {
+    private void setTargetRootTaskIfNeeded(ActivityRecord intentActivity, BalVerdict balVerdict) {
         intentActivity.getTaskFragment().clearLastPausedActivity();
         Task intentTask = intentActivity.getTask();
         // The intent task might be reparented while in getOrCreateRootTask, caches the original
@@ -2730,6 +2755,7 @@
                     // task on top there.
                     // Defer resuming the top activity while moving task to top, since the
                     // current task-top activity may not be the activity that should be resumed.
+                    logOnlyCreatorAllowsBAL(balVerdict, mRealCallingUid, false);
                     mTargetRootTask.moveTaskToFront(intentTask, mNoAnimation, mOptions,
                             mStartActivity.appTimeTracker, DEFER_RESUME,
                             "bringingFoundTaskToFront");
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index b66c4c3..287aaf9 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -433,10 +433,15 @@
     static class BalVerdict {
 
         static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, false, "Blocked");
+        static final BalVerdict ALLOW_BY_DEFAULT =
+                new BalVerdict(BAL_ALLOW_DEFAULT, false, "Default");
         private final @BalCode int mCode;
         private final boolean mBackground;
         private final String mMessage;
         private String mProcessInfo;
+        // indicates BAL would be blocked because only creator of the PI has the privilege to allow
+        // BAL, the sender does not have the privilege to allow BAL.
+        private boolean mOnlyCreatorAllows;
 
         BalVerdict(@BalCode int balCode, boolean background, String message) {
             this.mBackground = background;
@@ -457,6 +462,15 @@
             return !blocks();
         }
 
+        BalVerdict setOnlyCreatorAllows(boolean onlyCreatorAllows) {
+            mOnlyCreatorAllows = onlyCreatorAllows;
+            return this;
+        }
+
+        boolean onlyCreatorAllows() {
+            return mOnlyCreatorAllows;
+        }
+
         public String toString() {
             StringBuilder builder = new StringBuilder();
             builder.append(balCodeToString(mCode));
@@ -566,6 +580,10 @@
         BalVerdict resultForRealCaller = state.callerIsRealCaller() && resultForCaller.allows()
                 ? resultForCaller
                 : checkBackgroundActivityStartAllowedBySender(state, checkedOptions);
+        if (state.isPendingIntent()) {
+            resultForCaller.setOnlyCreatorAllows(
+                    resultForCaller.allows() && resultForRealCaller.blocks());
+        }
 
         if (resultForCaller.allows()
                 && checkedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
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 e2bb115..98055fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -118,6 +118,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
 import com.android.server.wm.utils.MockTracker;
 
@@ -1378,7 +1379,8 @@
                 .setUserId(10)
                 .build();
 
-        final int result = starter.recycleTask(task, null, null, null);
+        final int result = starter.recycleTask(task, null, null, null,
+                BalVerdict.ALLOW_BY_DEFAULT);
         assertThat(result == START_SUCCESS).isTrue();
         assertThat(starter.mAddingToTask).isTrue();
     }
@@ -1892,7 +1894,7 @@
         starter.startActivityInner(target, source, null /* voiceSession */,
                 null /* voiceInteractor */, 0 /* startFlags */,
                 options, inTask, inTaskFragment,
-                BackgroundActivityStartController.BAL_ALLOW_DEFAULT, null /* intentGrants */,
-                -1 /* realCallingUid */);
+                BalVerdict.ALLOW_BY_DEFAULT,
+                null /* intentGrants */, -1 /* realCallingUid */);
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index cf620fe..c404c77 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.server.wm.BackgroundActivityStartController.BalVerdict;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -186,7 +187,7 @@
                 /* options */null,
                 /* inTask */null,
                 /* inTaskFragment */ null,
-                /* balCode */ BackgroundActivityStartController.BAL_ALLOW_DEFAULT,
+                BalVerdict.ALLOW_BY_DEFAULT,
                 /* intentGrants */null,
                 /* realCaiingUid */ -1);
 
@@ -216,7 +217,7 @@
                 /* options= */null,
                 /* inTask= */null,
                 /* inTaskFragment= */ null,
-                /* balCode= */ BackgroundActivityStartController.BAL_ALLOW_DEFAULT,
+                BalVerdict.ALLOW_BY_DEFAULT,
                 /* intentGrants= */null,
                 /* realCaiingUid */ -1);