Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfd627c8 authored by Louis Chang's avatar Louis Chang
Browse files

Fix top app unable to start activity due to BAL

Application starts activity in Application#onCreate could be
blocked by BAL due to identifying a visible activity from
that app is not possible because the application process
has not yet fully attached.

Bug: 425287771
Test: BackgroundActivityStartControllerExemptionTests
Flag: EXEMPT bugfix
Change-Id: I275f990b255820fa0e9eca944140d2da2c21edcd
parent c3ec26a3
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.wm;

import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityOptions.BackgroundActivityStartMode;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS;
@@ -1096,11 +1097,11 @@ public class BackgroundActivityStartController {
                    mCheckCallerProcessInGracePeriod);
        }
        return evaluateChain(state, basedOnRealCaller, mCheckCallerVisible,
                mCheckCallerNonAppVisible, mCheckCallerProcessAllowsForeground,
                mCheckCallerIsAllowlistedUid, mCheckCallerIsAllowlistedComponent,
                mCheckCallerHasBackgroundPermission, mCheckCallerHasSawPermission,
                mCheckCallerHasBgStartAppOp, mCheckCallerProcessAllowsBackground,
                mCheckCallerProcessInGracePeriod);
                mCheckCallerNonAppVisible, mCheckCallerNonActivityTop,
                mCheckCallerProcessAllowsForeground, mCheckCallerIsAllowlistedUid,
                mCheckCallerIsAllowlistedComponent, mCheckCallerHasBackgroundPermission,
                mCheckCallerHasSawPermission, mCheckCallerHasBgStartAppOp,
                mCheckCallerProcessAllowsBackground, mCheckCallerProcessInGracePeriod);
    }

    interface BalExemptionCheck {
@@ -1149,6 +1150,18 @@ public class BackgroundActivityStartController {
        return BalVerdict.BLOCK;
    };

    private final BalExemptionCheck mCheckCallerNonActivityTop = state -> {
        // Allows if the UID process state is at the top and the app is not yet hosting any
        // activities. This is possible if the application starts an activity within its
        // `Application#onCreate` method when the process started, identifying a visible activity
        // from that app is not possible because the application process has not yet fully attached.
        if (state.mCallerApp != null && !state.mCallerApp.hasActivities()
                && state.mCallingUidProcState == PROCESS_STATE_TOP) {
            return new BalVerdict(BAL_ALLOW_FOREGROUND, "callingUid is the current top");
        }
        return BalVerdict.BLOCK;
    };

    private BalVerdict checkNonAppVisibleWindow(int uid, boolean hasNonAppVisibleWindow) {
        if (hasNonAppVisibleWindow) {
            SparseIntArray nonAppVisibleWindowDetails =
+42 −0
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

package com.android.server.wm;

import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;

import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT;
@@ -300,6 +302,46 @@ public class BackgroundActivityStartControllerExemptionTests {
                .isEqualTo(BAL_BLOCK);
    }

    @Test
    public void testCaller_appIsTop() {
        int callingUid = REGULAR_UID_1;
        int callingPid = REGULAR_PID_1;
        final String callingPackage = REGULAR_PACKAGE_1;
        int realCallingUid = REGULAR_UID_2;
        int realCallingPid = REGULAR_PID_2;

        // setup state
        when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(callingUid))).thenReturn(false);
        when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(callingUid)))
                .thenReturn(false);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);
        mActiveUids.onUidActive(callingUid, PROCESS_STATE_TOP);

        // prepare call
        PendingIntentRecord originatingPendingIntent = null;
        boolean allowBalExemptionForSystemProcess = false;
        Intent intent = TEST_INTENT;
        ActivityOptions checkedOptions = mCheckedOptions
                .setPendingIntentCreatorBackgroundActivityStartMode(
                        MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
        BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid,
                callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp,
                originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent,
                checkedOptions);
        assertThat(balState.toString()).contains("callingUidHasVisibleActivity: false");
        assertThat(balState.toString()).contains("callingUidHasVisibleNotPinnedActivity: false");
        assertThat(balState.toString()).contains("callingUidHasNonAppVisibleWindow: false");

        // call
        BalVerdict callerVerdict = mController.checkBackgroundActivityStartAllowedByCaller(
                balState);
        balState.setResultForCaller(callerVerdict);

        // assertions
        assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo(
                BAL_ALLOW_FOREGROUND);
    }

    @Test
    public void testCaller_appHasVisiblePinnedWindow() {
        int callingUid = REGULAR_UID_1;