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

Commit 35fe2782 authored by Achim Thesmann's avatar Achim Thesmann
Browse files

Implement ALLOW_IF_VISIBLE opt-in

If ALLOW_IF_VISIBLE is used only evauate the visibility based
exemptions.

Test: atest BackgroundActivityStartControllerExemptionTests BackgroundActivityStartControllerTests
Bug: 352182359
Flag: com.android.window.flags.bal_additional_start_modes
Change-Id: I36f5f7cdbff0ae8ff0d5775ff93682d0a9d4c896
parent 5afed3ad
Loading
Loading
Loading
Loading
+29 −5
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ 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.ActivityTaskSupervisor.getApplicationLabel;
import static com.android.server.wm.PendingRemoteAnimationRegistry.TIMEOUT_MS;
import static com.android.window.flags.Flags.balAdditionalStartModes;
import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg;
import static com.android.window.flags.Flags.balImproveRealCallerVisibilityCheck;
import static com.android.window.flags.Flags.balImprovedMetrics;
@@ -425,6 +426,8 @@ public class BackgroundActivityStartController {
                int callingUid, String callingPackage, ActivityOptions checkedOptions) {
            switch (checkedOptions.getPendingIntentCreatorBackgroundActivityStartMode()) {
                case MODE_BACKGROUND_ACTIVITY_START_ALLOWED:
                case MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE:
                case MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS:
                    return BackgroundStartPrivileges.ALLOW_BAL;
                case MODE_BACKGROUND_ACTIVITY_START_DENIED:
                    return BackgroundStartPrivileges.NONE;
@@ -840,12 +843,31 @@ public class BackgroundActivityStartController {
     * or {@link #BAL_BLOCK} if the launch should be blocked
     */
    BalVerdict checkBackgroundActivityStartAllowedByCaller(BalState state) {
        BalVerdict result = checkBackgroundActivityStartAllowedByCallerInForeground(state);
        if (state.isPendingIntent()) {
            // PendingIntents should mostly be allowed by the sender (real caller) or a permission
            // the creator of the PendingIntent has. Visibility should be the exceptional case, so
            // test it last (this does not change the result, just the bal code).
            BalVerdict result = BalVerdict.BLOCK;
            if (!(balAdditionalStartModes()
                    && state.mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
                    == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) {
                result = checkBackgroundActivityStartAllowedByCallerInBackground(state);
            }
            if (result == BalVerdict.BLOCK) {
                result = checkBackgroundActivityStartAllowedByCallerInForeground(state);

            }
            return result;
        } else {
            BalVerdict result = checkBackgroundActivityStartAllowedByCallerInForeground(state);
            if (result == BalVerdict.BLOCK && !(balAdditionalStartModes()
                    && state.mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
                    == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) {
                result = checkBackgroundActivityStartAllowedByCallerInBackground(state);
            }
            return result;
        }
    }

    /**
     * @return A code denoting which BAL rule allows an activity to be started,
@@ -966,7 +988,9 @@ public class BackgroundActivityStartController {
     */
    BalVerdict checkBackgroundActivityStartAllowedByRealCaller(BalState state) {
        BalVerdict result = checkBackgroundActivityStartAllowedByRealCallerInForeground(state);
        if (result == BalVerdict.BLOCK) {
        if (result == BalVerdict.BLOCK && !(balAdditionalStartModes()
                && state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
                == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) {
            result = checkBackgroundActivityStartAllowedByRealCallerInBackground(state);
        }
        return result;
+113 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.wm;

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 com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_ALLOWLISTED_COMPONENT;
@@ -25,6 +26,7 @@ import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_PERMISSION;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_SAW_PERMISSION;
import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_VISIBLE_WINDOW;
import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;

import static com.google.common.truth.Truth.assertWithMessage;

@@ -44,6 +46,7 @@ import android.content.Intent;
import android.content.pm.PackageManagerInternal;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.DeviceConfig;
@@ -55,6 +58,7 @@ import com.android.compatibility.common.util.DeviceConfigStateHelper;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.am.PendingIntentRecord;
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.window.flags.Flags;

import org.junit.After;
import org.junit.Before;
@@ -309,6 +313,76 @@ public class BackgroundActivityStartControllerExemptionTests {
                BAL_ALLOW_VISIBLE_WINDOW);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_BAL_ADDITIONAL_START_MODES)
    public void testCaller_appHasVisibleWindowWithIfVisibleOptIn() {
        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(mService.hasActiveVisibleWindow(eq(callingUid))).thenReturn(true);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

        // prepare call
        PendingIntentRecord originatingPendingIntent = mPendingIntentRecord;
        BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE;
        Intent intent = TEST_INTENT;
        ActivityOptions checkedOptions = mCheckedOptions
                .setPendingIntentCreatorBackgroundActivityStartMode(
                        MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE);
        BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid,
                callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp,
                originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent,
                checkedOptions);

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

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

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_BAL_ADDITIONAL_START_MODES)
    public void testRealCaller_appHasVisibleWindowWithIfVisibleOptIn() {
        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(mService.hasActiveVisibleWindow(eq(realCallingUid))).thenReturn(true);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

        // prepare call
        PendingIntentRecord originatingPendingIntent = mPendingIntentRecord;
        BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE;
        Intent intent = TEST_INTENT;
        ActivityOptions checkedOptions = mCheckedOptions
                .setPendingIntentCreatorBackgroundActivityStartMode(
                        MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE);
        BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid,
                callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp,
                originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent,
                checkedOptions);

        // call
        BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller(
                balState);
        balState.setResultForRealCaller(realCallerVerdict);

        // assertions
        assertWithMessage(balState.toString()).that(realCallerVerdict.getCode()).isEqualTo(
                BAL_ALLOW_VISIBLE_WINDOW);
    }

    @Test
    public void testCaller_appAllowedByBLPC() {
        // This covers the cases
@@ -470,6 +544,45 @@ public class BackgroundActivityStartControllerExemptionTests {
                BAL_ALLOW_ALLOWLISTED_COMPONENT);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_BAL_ADDITIONAL_START_MODES)
    public void testRealCaller_isCompanionAppWithOptInIfVisible() {
        // The app has a service that is bound by a different, visible app. The app bound to the
        // service must remain visible for the app in the background to start activities
        // successfully.
        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
        final int realCallingUserId = UserHandle.getUserId(realCallingUid);
        when(mService.isAssociatedCompanionApp(eq(realCallingUserId),
                eq(realCallingUid))).thenReturn(true);

        // prepare call
        PendingIntentRecord originatingPendingIntent = mPendingIntentRecord;
        BackgroundStartPrivileges forcedBalByPiSender = BackgroundStartPrivileges.NONE;
        Intent intent = TEST_INTENT;
        ActivityOptions checkedOptions = mCheckedOptions
                .setPendingIntentBackgroundActivityStartMode(
                        MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE);
        BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid,
                callingPid, callingPackage, realCallingUid, realCallingPid, null,
                originatingPendingIntent, forcedBalByPiSender, mResultRecord, intent,
                checkedOptions);

        // call
        BalVerdict realCallerVerdict = mController.checkBackgroundActivityStartAllowedByRealCaller(
                balState);
        balState.setResultForRealCaller(realCallerVerdict);

        // assertions
        assertWithMessage(balState.toString()).that(realCallerVerdict.getCode()).isEqualTo(
                BAL_BLOCK);
    }

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