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

Commit 2c84985e authored by Achim Thesmann's avatar Achim Thesmann Committed by Android Build Coastguard Worker
Browse files

Ignore pinned Windows

Pinned windows (e.g. PIP windows) should not enable BAL.

Test: atest BackgroundActivityLaunchTest BackgroundActivityStartController*Tests BackgroundLaunchProcessControllerTests
Flag: EXEMPT security fix
Bug: 406880479
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:accdba705e784ca8a90a62733e9ee44995d823b1)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:61eafea8fc148b173582a2e2687d4519c63026ff
Merged-In: I7ef4eb7123de24815703f4cc36cd192b6bca9517
Change-Id: I7ef4eb7123de24815703f4cc36cd192b6bca9517
parent 2eb771c8
Loading
Loading
Loading
Loading
+19 −4
Original line number Diff line number Diff line
@@ -309,6 +309,7 @@ public class BackgroundActivityStartController {
        private final int mCallingPid;
        private final @ActivityTaskManagerService.AppSwitchState int mAppSwitchState;
        private final boolean mCallingUidHasVisibleActivity;
        private final boolean mCallingUidHasVisibleNotPinnedActivity;
        private final boolean mCallingUidHasNonAppVisibleWindow;
        private final @ActivityManager.ProcessState int mCallingUidProcState;
        private final boolean mIsCallingUidPersistentSystemProcess;
@@ -318,6 +319,7 @@ public class BackgroundActivityStartController {
        private final int mRealCallingUid;
        private final int mRealCallingPid;
        private final boolean mRealCallingUidHasVisibleActivity;
        private final boolean mRealCallingUidHasVisibleNotPinnedActivity;
        private final boolean mRealCallingUidHasNonAppVisibleWindow;
        private final @ActivityManager.ProcessState int mRealCallingUidProcState;
        private final boolean mIsRealCallingUidPersistentSystemProcess;
@@ -408,6 +410,8 @@ public class BackgroundActivityStartController {
                    mCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
            mCallingUidHasVisibleActivity =
                    getService().mVisibleActivityProcessTracker.hasVisibleActivity(callingUid);
            mCallingUidHasVisibleNotPinnedActivity = getService().mVisibleActivityProcessTracker
                    .hasVisibleNotPinnedActivity(callingUid);
            mCallingUidHasNonAppVisibleWindow = getService().mActiveUids.hasNonAppVisibleWindow(
                    callingUid);
            if (realCallingUid == NO_PROCESS_UID) {
@@ -415,11 +419,13 @@ public class BackgroundActivityStartController {
                mRealCallingUidProcState = PROCESS_STATE_NONEXISTENT;
                mRealCallingUidHasVisibleActivity = false;
                mRealCallingUidHasNonAppVisibleWindow = false;
                mRealCallingUidHasVisibleNotPinnedActivity = false;
                mRealCallerApp = null;
                mIsRealCallingUidPersistentSystemProcess = false;
            } else if (callingUid == realCallingUid) {
                mRealCallingUidProcState = mCallingUidProcState;
                mRealCallingUidHasVisibleActivity = mCallingUidHasVisibleActivity;
                mRealCallingUidHasVisibleNotPinnedActivity = mCallingUidHasVisibleNotPinnedActivity;
                mRealCallingUidHasNonAppVisibleWindow = mCallingUidHasNonAppVisibleWindow;
                // In the PendingIntent case callerApp is not passed in, so resolve it ourselves.
                mRealCallerApp = callerApp == null
@@ -431,6 +437,9 @@ public class BackgroundActivityStartController {
                mRealCallingUidHasVisibleActivity =
                        getService().mVisibleActivityProcessTracker.hasVisibleActivity(
                                realCallingUid);
                mRealCallingUidHasVisibleNotPinnedActivity =
                        getService().mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(
                                realCallingUid);
                mRealCallingUidHasNonAppVisibleWindow =
                        getService().mActiveUids.hasNonAppVisibleWindow(realCallingUid);
                mRealCallerApp = getService().getProcessController(realCallingPid, realCallingUid);
@@ -564,6 +573,8 @@ public class BackgroundActivityStartController {
            sb.append("; callingPid: ").append(mCallingPid);
            sb.append("; appSwitchState: ").append(mAppSwitchState);
            sb.append("; callingUidHasVisibleActivity: ").append(mCallingUidHasVisibleActivity);
            sb.append("; callingUidHasVisibleNotPinnedActivity: ")
                    .append(mCallingUidHasVisibleNotPinnedActivity);
            sb.append("; callingUidHasNonAppVisibleWindow: ").append(
                    mCallingUidHasNonAppVisibleWindow);
            sb.append("; callingUidProcState: ").append(DebugUtils.valueToString(
@@ -598,6 +609,8 @@ public class BackgroundActivityStartController {
                sb.append("; realCallingPid: ").append(mRealCallingPid);
                sb.append("; realCallingUidHasVisibleActivity: ")
                        .append(mRealCallingUidHasVisibleActivity);
                sb.append("; realCallingUidHasVisibleNotPinnedActivity: ")
                        .append(mRealCallingUidHasVisibleNotPinnedActivity);
                sb.append("; realCallingUidHasNonAppVisibleWindow: ")
                        .append(mRealCallingUidHasNonAppVisibleWindow);
                sb.append("; realCallingUidProcState: ").append(DebugUtils.valueToString(
@@ -1037,8 +1050,9 @@ public class BackgroundActivityStartController {
        final boolean appSwitchAllowedOrFg = state.mAppSwitchState == APP_SWITCH_ALLOW
                || state.mAppSwitchState == APP_SWITCH_FG_ONLY
                || isHomeApp(state.mCallingUid, state.mCallingPackage);
        if (appSwitchAllowedOrFg && state.mCallingUidHasVisibleActivity) {
            return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "callingUid has visible window");
        if (appSwitchAllowedOrFg && state.mCallingUidHasVisibleNotPinnedActivity) {
            return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
                    "callingUid has visible non-pinned window");
        }
        return BalVerdict.BLOCK;
    };
@@ -1166,8 +1180,9 @@ public class BackgroundActivityStartController {
        final boolean appSwitchAllowedOrFg = state.mAppSwitchState == APP_SWITCH_ALLOW
                || state.mAppSwitchState == APP_SWITCH_FG_ONLY
                || isHomeApp(state.mRealCallingUid, state.mRealCallingPackage);
        if (appSwitchAllowedOrFg && state.mRealCallingUidHasVisibleActivity) {
            return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, "realCallingUid has visible window");
        if (appSwitchAllowedOrFg && state.mRealCallingUidHasVisibleNotPinnedActivity) {
            return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW,
                    "realCallingUid has visible non-pinned window");
        }
        return BalVerdict.BLOCK;
    };
+7 −4
Original line number Diff line number Diff line
@@ -120,7 +120,8 @@ class BackgroundLaunchProcessController {
    BalVerdict areBackgroundActivityStartsAllowed(
            int pid, int uid, String packageName,
            int appSwitchState, BalCheckConfiguration checkConfiguration,
            boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
            boolean hasActivityInVisibleTask, boolean inPinnedWindow,
            boolean hasBackgroundActivityStartPrivileges,
            long lastStopAppSwitchesTime, long lastActivityLaunchTime,
            long lastActivityFinishTime) {
        // Allow if the proc is instrumenting with background activity starts privs.
@@ -147,9 +148,11 @@ class BackgroundLaunchProcessController {
                    : BAL_ALLOW_VISIBLE_WINDOW, /*background*/
                    "process bound by foreground uid");
        }
        // Allow if the caller has an activity in any foreground task.
        if (checkConfiguration.checkOtherExemptions && hasActivityInVisibleTask
                && appSwitchState != APP_SWITCH_DISALLOW) {
        // Allow if the caller has an activity in any foreground task, unless it's a pinned window
        // and not a foreground service start.
        if ((checkConfiguration.isCheckingForFgsStart || !inPinnedWindow)
                && checkConfiguration.checkOtherExemptions
                && hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW) {
            return new BalVerdict(BAL_ALLOW_FOREGROUND, /*background*/
                    "process has activity in foreground task");
        }
+10 −2
Original line number Diff line number Diff line
@@ -80,14 +80,22 @@ class VisibleActivityProcessTracker {
     * {@link ActivityRecord#mVisibleRequested} or {@link ActivityRecord#isVisible()} is true.
     */
    boolean hasVisibleActivity(int uid) {
        return match(uid, null /* predicate */);
        return match(uid, WindowContainer.alwaysTruePredicate());
    }

    /**
     * Returns {@code true} if the uid has a process that contains an activity with
     * {@link ActivityRecord#mVisibleRequested} or {@link ActivityRecord#isVisible()} is true.
     */
    boolean hasVisibleNotPinnedActivity(int uid) {
        return match(uid, wpc -> !wpc.inPinnedWindowingMode());
    }

    private boolean match(int uid, Predicate<WindowProcessController> predicate) {
        synchronized (mProcMap) {
            for (int i = mProcMap.size() - 1; i >= 0; i--) {
                final WindowProcessController wpc = mProcMap.keyAt(i);
                if (wpc.mUid == uid && (predicate == null || predicate.test(wpc))) {
                if (wpc.mUid == uid && predicate.test(wpc)) {
                    return true;
                }
            }
+2 −1
Original line number Diff line number Diff line
@@ -727,7 +727,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
            int appSwitchState, BalCheckConfiguration checkConfiguration) {
        return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid,
                mInfo.packageName, appSwitchState, checkConfiguration,
                hasActivityInVisibleTask(), mInstrumentingWithBackgroundActivityStartPrivileges,
                hasActivityInVisibleTask(), inPinnedWindowingMode(),
                mInstrumentingWithBackgroundActivityStartPrivileges,
                mAtm.getLastStopAppSwitchesTime(),
                mLastActivityLaunchTime, mLastActivityFinishTime);
    }
+106 −8
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ 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.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.util.Pair;
import android.view.WindowManager;
@@ -64,6 +65,7 @@ import com.android.window.flags.Flags;

import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -88,6 +90,10 @@ import java.util.Set;
@RunWith(JUnit4.class)
public class BackgroundActivityStartControllerExemptionTests {

    @ClassRule
    public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
    @Rule public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();

    private static final int REGULAR_UID_1 = 10100;
    private static final int REGULAR_UID_2 = 10200;
    private static final int NO_UID = -1;
@@ -265,6 +271,8 @@ public class BackgroundActivityStartControllerExemptionTests {

        // setup state
        when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(callingUid))).thenReturn(true);
        when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(callingUid)))
                .thenReturn(false);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

        // prepare call
@@ -277,6 +285,7 @@ public class BackgroundActivityStartControllerExemptionTests {
                originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent,
                checkedOptions);
        assertThat(balState.toString()).contains("callingUidHasVisibleActivity: true");
        assertThat(balState.toString()).contains("callingUidHasVisibleNotPinnedActivity: false");
        assertThat(balState.toString()).contains("callingUidHasNonAppVisibleWindow: false");

        // call
@@ -285,8 +294,47 @@ public class BackgroundActivityStartControllerExemptionTests {
        balState.setResultForCaller(callerVerdict);

        // assertions
        assertWithMessage(balState.toString()).that(callerVerdict.getCode()).isEqualTo(
                BAL_ALLOW_VISIBLE_WINDOW);
        assertWithMessage(balState + " -> " + callerVerdict)
                .that(callerVerdict.getCode())
                .isEqualTo(BAL_BLOCK);
    }

    @Test
    public void testCaller_appHasVisiblePinnedWindow() {
        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(true);
        when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(callingUid)))
                .thenReturn(true);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

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

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

        // assertions
        assertWithMessage(balState + " -> " + callerVerdict)
                .that(callerVerdict.getCode())
                .isEqualTo(BAL_ALLOW_VISIBLE_WINDOW);
    }

    @Test
@@ -298,8 +346,10 @@ public class BackgroundActivityStartControllerExemptionTests {
        int realCallingPid = REGULAR_PID_2;

        // setup state
        when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(realCallingUid))).thenReturn(
                true);
        when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(realCallingUid)))
                .thenReturn(true);
        when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(realCallingUid)))
                .thenReturn(false);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

        // prepare call
@@ -312,6 +362,8 @@ public class BackgroundActivityStartControllerExemptionTests {
                originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent,
                checkedOptions);
        assertThat(balState.toString()).contains("realCallingUidHasVisibleActivity: true");
        assertThat(balState.toString())
                .contains("realCallingUidHasVisibleNotPinnedActivity: false");
        assertThat(balState.toString()).contains("realCallingUidHasNonAppVisibleWindow: false");

        // call
@@ -320,8 +372,48 @@ public class BackgroundActivityStartControllerExemptionTests {
        balState.setResultForRealCaller(realCallerVerdict);

        // assertions
        assertWithMessage(balState.toString()).that(realCallerVerdict.getCode()).isEqualTo(
                BAL_ALLOW_VISIBLE_WINDOW);
        assertWithMessage(balState + " -> " + realCallerVerdict)
                .that(realCallerVerdict.getCode())
                .isEqualTo(BAL_BLOCK);
    }

    @Test
    public void testRealCaller_appHasNotPinnedVisibleWindow() {
        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(realCallingUid)))
                .thenReturn(true);
        when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(realCallingUid)))
                .thenReturn(true);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

        // prepare call
        PendingIntentRecord originatingPendingIntent = mPendingIntentRecord;
        boolean allowBalExemptionForSystemProcess = false;
        Intent intent = TEST_INTENT;
        ActivityOptions checkedOptions = mCheckedOptions;
        BackgroundActivityStartController.BalState balState = mController.new BalState(callingUid,
                callingPid, callingPackage, realCallingUid, realCallingPid, mCallerApp,
                originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent,
                checkedOptions);
        assertThat(balState.toString()).contains("realCallingUidHasVisibleActivity: true");
        assertThat(balState.toString()).contains("realCallingUidHasVisibleNotPinnedActivity: true");
        assertThat(balState.toString()).contains("realCallingUidHasNonAppVisibleWindow: false");

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

        // assertions
        assertWithMessage(balState + " -> " + realCallerVerdict)
                .that(realCallerVerdict.getCode())
                .isEqualTo(BAL_ALLOW_VISIBLE_WINDOW);
    }

    @Test
@@ -405,6 +497,8 @@ public class BackgroundActivityStartControllerExemptionTests {

        // setup state
        when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(callingUid))).thenReturn(true);
        when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(callingUid)))
                .thenReturn(true);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

        // prepare call
@@ -419,6 +513,7 @@ public class BackgroundActivityStartControllerExemptionTests {
                originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent,
                checkedOptions);
        assertThat(balState.toString()).contains("callingUidHasVisibleActivity: true");
        assertThat(balState.toString()).contains("callingUidHasVisibleNotPinnedActivity: true");
        assertThat(balState.toString()).contains("callingUidHasNonAppVisibleWindow: false");

        // call
@@ -441,8 +536,10 @@ public class BackgroundActivityStartControllerExemptionTests {
        int realCallingPid = REGULAR_PID_2;

        // setup state
        when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(realCallingUid))).thenReturn(
                true);
        when(mVisibleActivityProcessTracker.hasVisibleActivity(eq(realCallingUid)))
                .thenReturn(true);
        when(mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(eq(realCallingUid)))
                .thenReturn(true);
        when(mService.getBalAppSwitchesState()).thenReturn(APP_SWITCH_ALLOW);

        // prepare call
@@ -457,6 +554,7 @@ public class BackgroundActivityStartControllerExemptionTests {
                originatingPendingIntent, allowBalExemptionForSystemProcess, mResultRecord, intent,
                checkedOptions);
        assertThat(balState.toString()).contains("realCallingUidHasVisibleActivity: true");
        assertThat(balState.toString()).contains("realCallingUidHasVisibleNotPinnedActivity: true");
        assertThat(balState.toString()).contains("realCallingUidHasNonAppVisibleWindow: false");

        // call
Loading