Merge "Update BAL Check to return Allow Reason" into tm-qpr-dev

Bug: 246738504
Test: atest ActivityStarterTests BackgroundActivityLaunchTest

Change-Id: Ie2bb56c53e49f6511a3e830ed1fa228b26e93a05
Merged-In: Ie2bb56c53e49f6511a3e830ed1fa228b26e93a05
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d6c1d7f..d1a5ead 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -74,6 +74,8 @@
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
 import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
@@ -130,6 +132,7 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 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.LaunchParamsController.LaunchParams;
 import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
 
@@ -171,9 +174,10 @@
     private int mCallingUid;
     private ActivityOptions mOptions;
 
-    // If it is true, background activity can only be started in an existing task that contains
+    // If it is BAL_BLOCK, background activity can only be started in an existing task that contains
     // an activity with same uid, or if activity starts are enabled in developer options.
-    private boolean mRestrictedBgActivity;
+    @BalCode
+    private int mBalCode;
 
     private int mLaunchMode;
     private boolean mLaunchTaskBehind;
@@ -589,7 +593,7 @@
         mIntent = starter.mIntent;
         mCallingUid = starter.mCallingUid;
         mOptions = starter.mOptions;
-        mRestrictedBgActivity = starter.mRestrictedBgActivity;
+        mBalCode = starter.mBalCode;
 
         mLaunchTaskBehind = starter.mLaunchTaskBehind;
         mLaunchFlags = starter.mLaunchFlags;
@@ -1020,15 +1024,15 @@
         ActivityOptions checkedOptions = options != null
                 ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
 
-        boolean restrictedBgActivity = false;
+        @BalCode int balCode = BAL_ALLOW_DEFAULT;
         if (!abort) {
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
                         "shouldAbortBackgroundActivityStart");
                 BackgroundActivityStartController balController =
                         mController.getBackgroundActivityLaunchController();
-                restrictedBgActivity =
-                        balController.shouldAbortBackgroundActivityStart(
+                balCode =
+                        balController.checkBackgroundActivityStart(
                                 callingUid,
                                 callingPid,
                                 callingPackage,
@@ -1216,13 +1220,13 @@
         WindowProcessController homeProcess = mService.mHomeProcess;
         boolean isHomeProcess = homeProcess != null
                 && aInfo.applicationInfo.uid == homeProcess.mUid;
-        if (!restrictedBgActivity && !isHomeProcess) {
+        if (balCode != BAL_BLOCK && !isHomeProcess) {
             mService.resumeAppSwitches();
         }
 
         mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                 request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
-                inTask, inTaskFragment, restrictedBgActivity, intentGrants);
+                inTask, inTaskFragment, balCode, intentGrants);
 
         if (request.outActivity != null) {
             request.outActivity[0] = mLastStartActivityRecord;
@@ -1372,7 +1376,7 @@
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, Task inTask,
-            TaskFragment inTaskFragment, boolean restrictedBgActivity,
+            TaskFragment inTaskFragment, @BalCode int balCode,
             NeededUriGrants intentGrants) {
         int result = START_CANCELED;
         final Task startedActivityRootTask;
@@ -1392,7 +1396,7 @@
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
                 result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
-                        startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
+                        startFlags, doResume, options, inTask, inTaskFragment, balCode,
                         intentGrants);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -1539,10 +1543,10 @@
     int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, Task inTask,
-            TaskFragment inTaskFragment, boolean restrictedBgActivity,
+            TaskFragment inTaskFragment, @BalCode int balCode,
             NeededUriGrants intentGrants) {
         setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
-                voiceSession, voiceInteractor, restrictedBgActivity);
+                voiceSession, voiceInteractor, balCode);
 
         computeLaunchingTaskFlags();
         mIntent.setFlags(mLaunchFlags);
@@ -1778,7 +1782,8 @@
                 || !targetTask.isUidPresent(mCallingUid)
                 || (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode()));
 
-        if (mRestrictedBgActivity && blockBalInTask && handleBackgroundActivityAbort(r)) {
+        if (mBalCode == BAL_BLOCK && blockBalInTask
+                && handleBackgroundActivityAbort(r)) {
             Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
             return START_ABORTED;
         }
@@ -2175,7 +2180,7 @@
         mIntent = null;
         mCallingUid = -1;
         mOptions = null;
-        mRestrictedBgActivity = false;
+        mBalCode = BAL_ALLOW_DEFAULT;
 
         mLaunchTaskBehind = false;
         mLaunchFlags = 0;
@@ -2220,7 +2225,7 @@
     private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
             TaskFragment inTaskFragment, boolean doResume, int startFlags,
             ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession,
-            IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) {
+            IVoiceInteractor voiceInteractor, @BalCode int balCode) {
         reset(false /* clearRequest */);
 
         mStartActivity = r;
@@ -2231,7 +2236,7 @@
         mSourceRootTask = mSourceRecord != null ? mSourceRecord.getRootTask() : null;
         mVoiceSession = voiceSession;
         mVoiceInteractor = voiceInteractor;
-        mRestrictedBgActivity = restrictedBgActivity;
+        mBalCode = balCode;
 
         mLaunchParams.reset();
 
@@ -2368,7 +2373,7 @@
 
         mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
 
-        if (mRestrictedBgActivity && !mService.isBackgroundActivityStartsEnabled()) {
+        if (mBalCode == BAL_BLOCK && !mService.isBackgroundActivityStartsEnabled()) {
             mAvoidMoveToFront = true;
             mDoResume = false;
         }
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index d515a27..2315795 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -25,6 +25,9 @@
 import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
 import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -39,6 +42,8 @@
 
 import com.android.server.am.PendingIntentRecord;
 
+import java.lang.annotation.Retention;
+
 /**
  * Helper class to check permissions for starting Activities.
  *
@@ -52,6 +57,56 @@
     private final ActivityTaskManagerService mService;
     private final ActivityTaskSupervisor mSupervisor;
 
+    // TODO(b/263368846) Rename when ASM logic is moved in
+    @Retention(SOURCE)
+    @IntDef({BAL_BLOCK,
+            BAL_ALLOW_DEFAULT,
+            BAL_ALLOW_ALLOWLISTED_UID,
+            BAL_ALLOW_ALLOWLISTED_COMPONENT,
+            BAL_ALLOW_VISIBLE_WINDOW,
+            BAL_ALLOW_PENDING_INTENT,
+            BAL_ALLOW_BAL_PERMISSION,
+            BAL_ALLOW_SAW_PERMISSION,
+            BAL_ALLOW_GRACE_PERIOD,
+            BAL_ALLOW_FOREGROUND,
+            BAL_ALLOW_SDK_SANDBOX
+    })
+    public @interface BalCode {}
+
+    static final int BAL_BLOCK = 0;
+
+    static final int BAL_ALLOW_DEFAULT = 1;
+
+    // Following codes are in order of precedence
+
+    /** Important UIDs which should be always allowed to launch activities */
+    static final int BAL_ALLOW_ALLOWLISTED_UID = 2;
+
+    /** Apps that fulfill a certain role that can can always launch new tasks */
+    static final int BAL_ALLOW_ALLOWLISTED_COMPONENT = 3;
+
+    /** Apps which currently have a visible window */
+    static final int BAL_ALLOW_VISIBLE_WINDOW = 4;
+
+    /** Allowed due to the PendingIntent sender */
+    static final int BAL_ALLOW_PENDING_INTENT = 5;
+
+    /** App has START_ACTIVITIES_FROM_BACKGROUND permission or BAL instrumentation privileges
+     * granted to it */
+    static final int BAL_ALLOW_BAL_PERMISSION = 6;
+
+    /** Process has SYSTEM_ALERT_WINDOW permission granted to it */
+    static final int BAL_ALLOW_SAW_PERMISSION = 7;
+
+    /** App is in grace period after an activity was started or finished */
+    static final int BAL_ALLOW_GRACE_PERIOD = 8;
+
+    /** App is in a foreground task or bound to a foreground service (but not itself visible) */
+    static final int BAL_ALLOW_FOREGROUND = 9;
+
+    /** Process belongs to a SDK sandbox */
+    static final int BAL_ALLOW_SDK_SANDBOX = 10;
+
     BackgroundActivityStartController(
             final ActivityTaskManagerService service, final ActivityTaskSupervisor supervisor) {
         mService = service;
@@ -83,6 +138,27 @@
             boolean allowBackgroundActivityStart,
             Intent intent,
             ActivityOptions checkedOptions) {
+        return checkBackgroundActivityStart(callingUid, callingPid, callingPackage,
+                realCallingUid, realCallingPid, callerApp, originatingPendingIntent,
+                allowBackgroundActivityStart, intent, checkedOptions) == BAL_BLOCK;
+    }
+
+    /**
+     * @return A code denoting which BAL rule allows an activity to be started,
+     * or {@link BAL_BLOCK} if the launch should be blocked
+     */
+    @BalCode
+    int checkBackgroundActivityStart(
+            int callingUid,
+            int callingPid,
+            final String callingPackage,
+            int realCallingUid,
+            int realCallingPid,
+            WindowProcessController callerApp,
+            PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart,
+            Intent intent,
+            ActivityOptions checkedOptions) {
         // don't abort for the most important UIDs
         final int callingAppId = UserHandle.getAppId(callingUid);
         final boolean useCallingUidState =
@@ -93,32 +169,22 @@
             if (callingUid == Process.ROOT_UID
                     || callingAppId == Process.SYSTEM_UID
                     || callingAppId == Process.NFC_UID) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Activity start allowed for important callingUid (" + callingUid + ")");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
+                        BAL_ALLOW_ALLOWLISTED_UID, "Important callingUid");
             }
 
             // Always allow home application to start activities.
             if (isHomeApp(callingUid, callingPackage)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Activity start allowed for home app callingUid (" + callingUid + ")");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
+                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Home app");
             }
 
             // IME should always be allowed to start activity, like IME settings.
             final WindowState imeWindow =
                     mService.mRootWindowContainer.getCurrentInputMethodWindow();
             if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed for active ime (" + callingUid + ")");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
+                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Active ime");
             }
         }
 
@@ -145,15 +211,12 @@
                                 && callingUidHasAnyVisibleWindow)
                         || isCallingUidPersistentSystemProcess;
         if (useCallingUidState && allowCallingUidStartActivity) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(
-                        TAG,
-                        "Activity start allowed: callingUidHasAnyVisibleWindow = "
-                                + callingUid
-                                + ", isCallingUidPersistentSystemProcess = "
-                                + isCallingUidPersistentSystemProcess);
-            }
-            return false;
+            return logStartAllowedAndReturnCode(/*background*/ false,
+                    BAL_ALLOW_VISIBLE_WINDOW,
+                    "callingUidHasAnyVisibleWindow = "
+                            + callingUid
+                            + ", isCallingUidPersistentSystemProcess = "
+                            + isCallingUidPersistentSystemProcess);
         }
         // take realCallingUid into consideration
         final int realCallingUidProcState =
@@ -184,14 +247,9 @@
                     Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
 
             if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Activity start allowed: uid in SDK sandbox ("
-                                    + realCallingUid
-                                    + ") has visible (non-toast) window.");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false, realCallingUid,
+                        BAL_ALLOW_SDK_SANDBOX,
+                        "uid in SDK sandbox has visible (non-toast) window");
             }
         }
 
@@ -209,100 +267,60 @@
                                     -1,
                                     true)
                             == PackageManager.PERMISSION_GRANTED) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Activity start allowed: realCallingUid ("
-                                    + realCallingUid
-                                    + ") has BAL permission.");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
+                        BAL_ALLOW_PENDING_INTENT,
+                        "realCallingUid has BAL permission. realCallingUid: " + realCallingUid);
             }
 
             // don't abort if the realCallingUid has a visible window
             // TODO(b/171459802): We should check appSwitchAllowed also
             if (realCallingUidHasAnyVisibleWindow) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Activity start allowed: realCallingUid ("
-                                    + realCallingUid
-                                    + ") has visible (non-toast) window");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false,
+                        callingUid, BAL_ALLOW_PENDING_INTENT,
+                        "realCallingUid has visible (non-toast) window. realCallingUid: "
+                                + realCallingUid);
             }
             // if the realCallingUid is a persistent system process, abort if the IntentSender
             // wasn't allowed to start an activity
             if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Activity start allowed: realCallingUid ("
-                                    + realCallingUid
-                                    + ") is persistent system process AND intent sender allowed "
-                                    + "(allowBackgroundActivityStart = true)");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false,
+                        callingUid,
+                        BAL_ALLOW_PENDING_INTENT,
+                        "realCallingUid is persistent system process AND intent "
+                                + "sender allowed (allowBackgroundActivityStart = true). "
+                                + "realCallingUid: " + realCallingUid);
             }
             // don't abort if the realCallingUid is an associated companion app
             if (mService.isAssociatedCompanionApp(
                     UserHandle.getUserId(realCallingUid), realCallingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Activity start allowed: realCallingUid ("
-                                    + realCallingUid
-                                    + ") is companion app");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ false, callingUid,
+                        BAL_ALLOW_PENDING_INTENT,  "realCallingUid is a companion app. "
+                                + "realCallingUid: " + realCallingUid);
             }
         }
         if (useCallingUidState) {
             // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
-            if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
-                    == PERMISSION_GRANTED) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND "
-                                    + "permission granted for uid "
-                                    + callingUid);
-                }
-                return false;
+            if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND,
+                    callingPid, callingUid) == PERMISSION_GRANTED) {
+                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
+                        BAL_ALLOW_BAL_PERMISSION,
+                        "START_ACTIVITIES_FROM_BACKGROUND permission granted");
             }
             // don't abort if the caller has the same uid as the recents component
             if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Background activity start allowed: callingUid ("
-                                    + callingUid
-                                    + ") is recents");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
+                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Recents Component");
             }
             // don't abort if the callingUid is the device owner
             if (mService.isDeviceOwner(callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Background activity start allowed: callingUid ("
-                                    + callingUid
-                                    + ") is device owner");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
+                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Device Owner");
             }
             // don't abort if the callingUid has companion device
             final int callingUserId = UserHandle.getUserId(callingUid);
             if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Background activity start allowed: callingUid ("
-                                    + callingUid
-                                    + ") is companion app");
-                }
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
+                        BAL_ALLOW_ALLOWLISTED_COMPONENT, "Companion App");
             }
             // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
             if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
@@ -311,7 +329,8 @@
                         "Background activity start for "
                                 + callingPackage
                                 + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
-                return false;
+                return logStartAllowedAndReturnCode(/*background*/ true, callingUid,
+                        BAL_ALLOW_SAW_PERMISSION, "SYSTEM_ALERT_WINDOW permission is granted");
             }
         }
         // If we don't have callerApp at this point, no caller was provided to startActivity().
@@ -326,17 +345,12 @@
         // don't abort if the callerApp or other processes of that uid are allowed in any way
         if (callerApp != null && useCallingUidState) {
             // first check the original calling process
-            if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(
-                            TAG,
-                            "Background activity start allowed: callerApp process (pid = "
-                                    + callerApp.getPid()
-                                    + ", uid = "
-                                    + callerAppUid
-                                    + ") is allowed");
-                }
-                return false;
+            @BalCode int balAllowedForCaller = callerApp
+                    .areBackgroundActivityStartsAllowed(appSwitchState);
+            if (balAllowedForCaller != BAL_BLOCK) {
+                return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForCaller,
+                        "callerApp process (pid = " + callerApp.getPid()
+                                + ", uid = " + callerAppUid + ") is allowed");
             }
             // only if that one wasn't allowed, check the other ones
             final ArraySet<WindowProcessController> uidProcesses =
@@ -344,18 +358,12 @@
             if (uidProcesses != null) {
                 for (int i = uidProcesses.size() - 1; i >= 0; i--) {
                     final WindowProcessController proc = uidProcesses.valueAt(i);
+                    int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState);
                     if (proc != callerApp
-                            && proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
-                        if (DEBUG_ACTIVITY_STARTS) {
-                            Slog.d(
-                                    TAG,
-                                    "Background activity start allowed: process "
-                                            + proc.getPid()
-                                            + " from uid "
-                                            + callerAppUid
-                                            + " is allowed");
-                        }
-                        return false;
+                            && balAllowedForUid != BAL_BLOCK) {
+                        return logStartAllowedAndReturnCode(/*background*/ true, balAllowedForUid,
+                                "process" + proc.getPid()
+                                        + " from uid " + callerAppUid + " is allowed");
                     }
                 }
             }
@@ -416,6 +424,34 @@
                             realCallingUidHasAnyVisibleWindow,
                             (originatingPendingIntent != null));
         }
-        return true;
+        return BAL_BLOCK;
+    }
+
+    private int logStartAllowedAndReturnCode(boolean background, int callingUid, int code,
+            String msg) {
+        if (DEBUG_ACTIVITY_STARTS) {
+            return logStartAllowedAndReturnCode(background, code,
+                    msg, "callingUid: " + callingUid);
+        }
+        return code;
+    }
+
+    private int logStartAllowedAndReturnCode(boolean background, int code,
+            String... msg) {
+        if (DEBUG_ACTIVITY_STARTS) {
+            StringBuilder builder = new StringBuilder();
+            if (background) {
+                builder.append("Background ");
+            }
+            builder.append("Activity start allowed: ");
+            for (int i = 0; i < msg.length; i++) {
+                builder.append(msg[i]);
+                builder.append(". ");
+            }
+            builder.append("BAL Code: ");
+            builder.append(code);
+            Slog.d(TAG,  builder.toString());
+        }
+        return code;
     }
 }
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 0afd872..020e9c58 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -22,6 +22,10 @@
 import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
 import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
 import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -71,7 +75,8 @@
         mBackgroundActivityStartCallback = callback;
     }
 
-    boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
+    @BackgroundActivityStartController.BalCode
+    int areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
             int appSwitchState, boolean isCheckingForFgsStart,
             boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
             long lastStopAppSwitchesTime, long lastActivityLaunchTime,
@@ -93,7 +98,7 @@
                                 + ")] Activity start allowed: within "
                                 + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
                     }
-                    return true;
+                    return BAL_ALLOW_GRACE_PERIOD;
                 }
                 if (DEBUG_ACTIVITY_STARTS) {
                     Slog.d(TAG, "[Process(" + pid + ")] Activity start within "
@@ -110,7 +115,7 @@
                         + ")] Activity start allowed: process instrumenting with background "
                         + "activity starts privileges");
             }
-            return true;
+            return BAL_ALLOW_BAL_PERMISSION;
         }
         // Allow if the caller has an activity in any foreground task.
         if (hasActivityInVisibleTask
@@ -119,7 +124,7 @@
                 Slog.d(TAG, "[Process(" + pid
                         + ")] Activity start allowed: process has activity in foreground task");
             }
-            return true;
+            return BAL_ALLOW_FOREGROUND;
         }
         // Allow if the caller is bound by a UID that's currently foreground.
         if (isBoundByForegroundUid()) {
@@ -127,7 +132,7 @@
                 Slog.d(TAG, "[Process(" + pid
                         + ")] Activity start allowed: process bound by foreground uid");
             }
-            return true;
+            return BAL_ALLOW_FOREGROUND;
         }
         // Allow if the flag was explicitly set.
         if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
@@ -135,9 +140,9 @@
                 Slog.d(TAG, "[Process(" + pid
                         + ")] Activity start allowed: process allowed by token");
             }
-            return true;
+            return BAL_ALLOW_BAL_PERMISSION;
         }
-        return false;
+        return BAL_BLOCK;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 682918b..0479920 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -40,6 +40,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 import static com.android.server.wm.WindowManagerService.MY_PID;
 
 import android.Manifest;
@@ -544,15 +545,17 @@
     @HotPath(caller = HotPath.START_SERVICE)
     public boolean areBackgroundFgsStartsAllowed() {
         return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesState(),
-                true /* isCheckingForFgsStart */);
+                true /* isCheckingForFgsStart */) != BAL_BLOCK;
     }
 
-    boolean areBackgroundActivityStartsAllowed(int appSwitchState) {
+    @BackgroundActivityStartController.BalCode
+    int areBackgroundActivityStartsAllowed(int appSwitchState) {
         return areBackgroundActivityStartsAllowed(appSwitchState,
                 false /* isCheckingForFgsStart */);
     }
 
-    private boolean areBackgroundActivityStartsAllowed(int appSwitchState,
+    @BackgroundActivityStartController.BalCode
+    private int areBackgroundActivityStartsAllowed(int appSwitchState,
             boolean isCheckingForFgsStart) {
         return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName,
                 appSwitchState, isCheckingForFgsStart, hasActivityInVisibleTask(),
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 e8d5c00..1d859bf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1497,7 +1497,7 @@
             TaskFragment inTaskFragment) {
         starter.startActivityInner(target, source, null /* voiceSession */,
                 null /* voiceInteractor */, 0 /* startFlags */, true /* doResume */,
-                options, inTask, inTaskFragment, false /* restrictedBgActivity */,
-                null /* intentGrants */);
+                options, inTask, inTaskFragment,
+                BackgroundActivityStartController.BAL_ALLOW_DEFAULT, null /* intentGrants */);
     }
 }
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 47c2176..b7f8564 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -188,7 +188,7 @@
                 /* options */null,
                 /* inTask */null,
                 /* inTaskFragment */ null,
-                /* restrictedBgActivity */false,
+                /* balCode */ BackgroundActivityStartController.BAL_ALLOW_DEFAULT,
                 /* intentGrants */null);
 
         assertEquals(result, START_ABORTED);