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

Commit c53e36a6 authored by Achim Thesmann's avatar Achim Thesmann Committed by Android (Google) Code Review
Browse files

Merge changes I36f5f7cd,Idb69119a,I5740fea0 into main

* changes:
  Implement ALLOW_IF_VISIBLE opt-in
  Split checks for visibility and other exemptions
  Introduce BAL Configuration object
parents 3131d5db 35fe2782
Loading
Loading
Loading
Loading
+88 −25
Original line number Diff line number Diff line
@@ -21,10 +21,10 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
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;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_COMPAT;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
@@ -39,13 +39,15 @@ import static com.android.server.wm.ActivityStarter.ASM_RESTRICTIONS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
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.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.balImprovedMetrics;
import static com.android.window.flags.Flags.balImproveRealCallerVisibilityCheck;
import static com.android.window.flags.Flags.balImprovedMetrics;
import static com.android.window.flags.Flags.balRequireOptInByPendingIntentCreator;
import static com.android.window.flags.Flags.balRequireOptInSameUid;
import static com.android.window.flags.Flags.balRespectAppSwitchStateWhenCheckBoundByForegroundUid;
@@ -84,6 +86,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.server.UiThread;
import com.android.server.am.PendingIntentRecord;
import com.android.server.wm.BackgroundLaunchProcessController.BalCheckConfiguration;

import java.lang.annotation.Retention;
import java.util.ArrayList;
@@ -107,6 +110,17 @@ public class BackgroundActivityStartController {
    private static final int ASM_GRACEPERIOD_MAX_REPEATS = 5;
    private static final int NO_PROCESS_UID = -1;

    private static final BalCheckConfiguration BAL_CHECK_FOREGROUND = new BalCheckConfiguration(
            /* isCheckingForFgsStarts */ false,
            /* checkVisibility */ true,
            /* checkOtherExemptions */ false,
            ACTIVITY_BG_START_GRACE_PERIOD_MS);
    private static final BalCheckConfiguration BAL_CHECK_BACKGROUND = new BalCheckConfiguration(
            /* isCheckingForFgsStarts */ false,
            /* checkVisibility */ false,
            /* checkOtherExemptions */ true,
            ACTIVITY_BG_START_GRACE_PERIOD_MS);

    static final String AUTO_OPT_IN_NOT_PENDING_INTENT = "notPendingIntent";
    static final String AUTO_OPT_IN_CALL_FOR_RESULT = "callForResult";
    static final String AUTO_OPT_IN_SAME_UID = "sameUid";
@@ -412,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;
@@ -752,7 +768,7 @@ public class BackgroundActivityStartController {
        // PendingIntents is null).
        BalVerdict resultForRealCaller = state.callerIsRealCaller() && resultForCaller.allows()
                ? resultForCaller
                : checkBackgroundActivityStartAllowedBySender(state)
                : checkBackgroundActivityStartAllowedByRealCaller(state)
                        .setBasedOnRealCaller();
        state.setResultForRealCaller(resultForRealCaller);

@@ -827,6 +843,37 @@ public class BackgroundActivityStartController {
     * or {@link #BAL_BLOCK} if the launch should be blocked
     */
    BalVerdict checkBackgroundActivityStartAllowedByCaller(BalState 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,
     * or {@link #BAL_BLOCK} if the launch should be blocked
     */
    BalVerdict checkBackgroundActivityStartAllowedByCallerInForeground(BalState state) {
        // This is used to block background activity launch even if the app is still
        // visible to user after user clicking home button.

@@ -842,7 +889,16 @@ public class BackgroundActivityStartController {
            return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW,
                    /*background*/ false, "callingUid has non-app visible window");
        }
        // Don't abort if the callerApp or other processes of that uid are considered to be in the
        // foreground.
        return checkProcessAllowsBal(state.mCallerApp, state, BAL_CHECK_FOREGROUND);
    }

    /**
     * @return A code denoting which BAL rule allows an activity to be started,
     * or {@link #BAL_BLOCK} if the launch should be blocked
     */
    BalVerdict checkBackgroundActivityStartAllowedByCallerInBackground(BalState state) {
        // don't abort for the most important UIDs
        final int callingAppId = UserHandle.getAppId(state.mCallingUid);
        if (state.mCallingUid == Process.ROOT_UID
@@ -922,25 +978,29 @@ public class BackgroundActivityStartController {
                    "OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
        }

        // If we don't have callerApp at this point, no caller was provided to startActivity().
        // That's the case for PendingIntent-based starts, since the creator's process might not be
        // up and alive.
        // Don't abort if the callerApp or other processes of that uid are allowed in any way.
        BalVerdict callerAppAllowsBal = checkProcessAllowsBal(state.mCallerApp, state);
        if (callerAppAllowsBal.allows()) {
            return callerAppAllowsBal;
        return checkProcessAllowsBal(state.mCallerApp, state, BAL_CHECK_BACKGROUND);
    }

        // If we are here, it means all exemptions based on the creator failed
        return BalVerdict.BLOCK;
    /**
     * @return A code denoting which BAL rule allows an activity to be started,
     * or {@link #BAL_BLOCK} if the launch should be blocked
     */
    BalVerdict checkBackgroundActivityStartAllowedByRealCaller(BalState state) {
        BalVerdict result = checkBackgroundActivityStartAllowedByRealCallerInForeground(state);
        if (result == BalVerdict.BLOCK && !(balAdditionalStartModes()
                && state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
                == MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE)) {
            result = checkBackgroundActivityStartAllowedByRealCallerInBackground(state);
        }
        return result;
    }

    /**
     * @return A code denoting which BAL rule allows an activity to be started,
     * or {@link #BAL_BLOCK} if the launch should be blocked
     */
    BalVerdict checkBackgroundActivityStartAllowedBySender(BalState state) {

    BalVerdict checkBackgroundActivityStartAllowedByRealCallerInForeground(BalState state) {
        // Normal apps with visible app window will be allowed to start activity if app switching
        // is allowed, or apps like live wallpaper with non app visible window will be allowed.
        // The home app can start apps even if app switches are usually disallowed.
@@ -966,6 +1026,16 @@ public class BackgroundActivityStartController {
            }
        }

        // Don't abort if the realCallerApp or other processes of that uid are considered to be in
        // the foreground.
        return checkProcessAllowsBal(state.mRealCallerApp, state, BAL_CHECK_FOREGROUND);
    }

    /**
     * @return A code denoting which BAL rule allows an activity to be started,
     * or {@link #BAL_BLOCK} if the launch should be blocked
     */
    BalVerdict checkBackgroundActivityStartAllowedByRealCallerInBackground(BalState state) {
        if (state.mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
                == MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
                && hasBalPermission(state.mRealCallingUid, state.mRealCallingPid)) {
@@ -992,14 +1062,7 @@ public class BackgroundActivityStartController {
        }

        // don't abort if the callerApp or other processes of that uid are allowed in any way
        BalVerdict realCallerAppAllowsBal =
                checkProcessAllowsBal(state.mRealCallerApp, state);
        if (realCallerAppAllowsBal.allows()) {
            return realCallerAppAllowsBal;
        }

        // If we are here, it means all exemptions based on PI sender failed
        return BalVerdict.BLOCK;
        return checkProcessAllowsBal(state.mRealCallerApp, state, BAL_CHECK_BACKGROUND);
    }

    @VisibleForTesting boolean hasBalPermission(int uid, int pid) {
@@ -1015,13 +1078,13 @@ public class BackgroundActivityStartController {
     * exceptions.
     */
    @VisibleForTesting BalVerdict checkProcessAllowsBal(WindowProcessController app,
            BalState state) {
            BalState state, BalCheckConfiguration balCheckConfiguration) {
        if (app == null) {
            return BalVerdict.BLOCK;
        }
        // first check the original calling process
        final BalVerdict balAllowedForCaller = app
                .areBackgroundActivityStartsAllowed(state.mAppSwitchState);
                .areBackgroundActivityStartsAllowed(state.mAppSwitchState, balCheckConfiguration);
        if (balAllowedForCaller.allows()) {
            return balAllowedForCaller.withProcessInfo("callerApp process", app);
        } else {
@@ -1033,7 +1096,7 @@ public class BackgroundActivityStartController {
                    final WindowProcessController proc = uidProcesses.valueAt(i);
                    if (proc != app) {
                        BalVerdict balAllowedForUid = proc.areBackgroundActivityStartsAllowed(
                                state.mAppSwitchState);
                                state.mAppSwitchState, balCheckConfiguration);
                        if (balAllowedForUid.allows()) {
                            return balAllowedForUid.withProcessInfo("process", proc);
                        }
+32 −11
Original line number Diff line number Diff line
@@ -98,42 +98,63 @@ class BackgroundLaunchProcessController {
        mBackgroundActivityStartCallback = callback;
    }

    record BalCheckConfiguration(
            boolean isCheckingForFgsStart,
            boolean checkVisibility,
            boolean checkOtherExemptions,
            long gracePeriod
    ) {
    }

    /**
     * Check configuration for foreground service starts.
     *
     * The check executes all parts of the BAL checks and uses the same grace period,
     * so FGS is allowed whenever BAL is allowed.
     */
    static final BalCheckConfiguration CHECK_FOR_FGS_START = new BalCheckConfiguration(
            /* isCheckingForFgsStarts */ true,
            /* checkVisibility */ true,
            /* checkOtherExemptions */ true,
            ACTIVITY_BG_START_GRACE_PERIOD_MS);

    BalVerdict areBackgroundActivityStartsAllowed(
            int pid, int uid, String packageName,
            int appSwitchState, boolean isCheckingForFgsStart,
            int appSwitchState, BalCheckConfiguration checkConfiguration,
            boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
            long lastStopAppSwitchesTime, long lastActivityLaunchTime,
            long lastActivityFinishTime) {
        // Allow if the proc is instrumenting with background activity starts privs.
        if (hasBackgroundActivityStartPrivileges) {
        if (checkConfiguration.checkOtherExemptions && hasBackgroundActivityStartPrivileges) {
            return new BalVerdict(BAL_ALLOW_PERMISSION, /*background*/ true,
                    "process instrumenting with background activity starts privileges");
        }
        // Allow if the flag was explicitly set.
        if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) {
        if (checkConfiguration.checkOtherExemptions && isBackgroundStartAllowedByToken(uid,
                packageName, checkConfiguration.isCheckingForFgsStart)) {
            return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_TOKEN : BAL_ALLOW_PERMISSION,
                    /*background*/ true, "process allowed by token");
        }
        // Allow if the caller is bound by a UID that's currently foreground.
        // But still respect the appSwitchState.
        boolean allowBoundByForegroundUid =
        if (checkConfiguration.checkVisibility && (
                Flags.balRespectAppSwitchStateWhenCheckBoundByForegroundUid()
                        ? appSwitchState != APP_SWITCH_DISALLOW && isBoundByForegroundUid()
                : isBoundByForegroundUid();
        if (allowBoundByForegroundUid) {
                        : isBoundByForegroundUid())) {
            return new BalVerdict(balImprovedMetrics() ? BAL_ALLOW_BOUND_BY_FOREGROUND
                    : BAL_ALLOW_VISIBLE_WINDOW, /*background*/ false,
                    "process bound by foreground uid");
        }
        // Allow if the caller has an activity in any foreground task.
        if (hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW) {
        if (checkConfiguration.checkVisibility && hasActivityInVisibleTask
                && appSwitchState != APP_SWITCH_DISALLOW) {
            return new BalVerdict(BAL_ALLOW_FOREGROUND, /*background*/ false,
                    "process has activity in foreground task");
        }

        // If app switching is not allowed, we ignore all the start activity grace period
        // exception so apps cannot start itself in onPause() after pressing home button.
        if (appSwitchState == APP_SWITCH_ALLOW) {
        if (checkConfiguration.checkOtherExemptions && appSwitchState == APP_SWITCH_ALLOW) {
            // Allow if any activity in the caller has either started or finished very recently, and
            // it must be started or finished after last stop app switches time.
            if (lastActivityLaunchTime > lastStopAppSwitchesTime
@@ -141,9 +162,9 @@ class BackgroundLaunchProcessController {
                final long now = SystemClock.uptimeMillis();
                long timeSinceLastStartOrFinish = now - Math.max(lastActivityLaunchTime,
                        lastActivityFinishTime);
                if (timeSinceLastStartOrFinish < ACTIVITY_BG_START_GRACE_PERIOD_MS) {
                if (timeSinceLastStartOrFinish < checkConfiguration.gracePeriod) {
                    return new BalVerdict(BAL_ALLOW_GRACE_PERIOD, /*background*/ true,
                            "within " + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period ("
                            "within " + checkConfiguration.gracePeriod + "ms grace period ("
                                    + timeSinceLastStartOrFinish + "ms)");
                }
            }
+4 −10
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
import com.android.server.wm.ActivityTaskManagerService.HotPath;
import com.android.server.wm.BackgroundLaunchProcessController.BalCheckConfiguration;

import java.io.IOException;
import java.io.PrintWriter;
@@ -695,20 +696,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
    public boolean areBackgroundFgsStartsAllowed() {
        return areBackgroundActivityStartsAllowed(
                mAtm.getBalAppSwitchesState(),
                true /* isCheckingForFgsStart */).allows();
                BackgroundLaunchProcessController.CHECK_FOR_FGS_START).allows();
    }

    BackgroundActivityStartController.BalVerdict areBackgroundActivityStartsAllowed(
            int appSwitchState) {
        return areBackgroundActivityStartsAllowed(
                appSwitchState,
                false /* isCheckingForFgsStart */);
    }

    private BackgroundActivityStartController.BalVerdict areBackgroundActivityStartsAllowed(
            int appSwitchState, boolean isCheckingForFgsStart) {
            int appSwitchState, BalCheckConfiguration checkConfiguration) {
        return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid,
                mInfo.packageName, appSwitchState, isCheckingForFgsStart,
                mInfo.packageName, appSwitchState, checkConfiguration,
                hasActivityInVisibleTask(), mInstrumentingWithBackgroundActivityStartPrivileges,
                mAtm.getLastStopAppSwitchesTime(),
                mLastActivityLaunchTime, mLastActivityFinishTime);
+130 −12

File changed.

Preview size limit exceeded, changes collapsed.

+8 −5
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static com.android.window.flags.Flags.balImprovedMetrics;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -43,6 +44,7 @@ import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.DeviceConfigStateHelper;
import com.android.server.am.PendingIntentRecord;
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.server.wm.BackgroundLaunchProcessController.BalCheckConfiguration;

import org.junit.After;
import org.junit.Before;
@@ -167,9 +169,9 @@ public class BackgroundActivityStartControllerTests {
        }

        @Override
        BalVerdict checkBackgroundActivityStartAllowedBySender(BalState state) {
        BalVerdict checkBackgroundActivityStartAllowedByRealCaller(BalState state) {
            return mRealCallerVerdict.orElseGet(
                    () -> super.checkBackgroundActivityStartAllowedBySender(state));
                    () -> super.checkBackgroundActivityStartAllowedByRealCaller(state));
        }

        public void setRealCallerVerdict(BalVerdict verdict) {
@@ -177,11 +179,12 @@ public class BackgroundActivityStartControllerTests {
        }

        @Override
        BalVerdict checkProcessAllowsBal(WindowProcessController app, BalState state) {
        BalVerdict checkProcessAllowsBal(WindowProcessController app, BalState state,
                BalCheckConfiguration checkConfiguration) {
            if (mProcessVerdicts.containsKey(app)) {
                return mProcessVerdicts.get(app);
            }
            return super.checkProcessAllowsBal(app, state);
            return super.checkProcessAllowsBal(app, state, checkConfiguration);
        }
    }

@@ -209,7 +212,7 @@ public class BackgroundActivityStartControllerTests {
        Mockito.when(mAppOpsManager.checkOpNoThrow(
                eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION),
                anyInt(), anyString())).thenReturn(AppOpsManager.MODE_DEFAULT);
        Mockito.when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt())).thenReturn(
        Mockito.when(mCallerApp.areBackgroundActivityStartsAllowed(anyInt(), any())).thenReturn(
                BalVerdict.BLOCK);
    }

Loading