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

Commit 9268360c authored by Ricky Wai's avatar Ricky Wai
Browse files

Introduce Background Activity Launch home mode

Background activity launch home mode will replace existing app
switch protection logic.

After user processing home button, all normal apps, including
ui visible apps, will no longer able to start background
activity even its within grace period, except the apps that
have permission to start background activity. This will stop
apps try to start itself during onPause() after pressing home button.

It removes the pending activity queue in the origianl
apps switching protection due to confusing UX. Also, it removes
the logic that stop app switching protection after 5 second timeout.

Bug: 159433730
Test: Create an app that startActivity in onPause(), then click home
button. Activity can be started in its background task but not a new
foreground task.
Test: Create an app and enter pip mode in background and start new
activity task. After pressing home button, apps can enter pip mode
but cannot create a new task.

Change-Id: Iaa77daba2fbce68f65a60ca71969c3f18bac3684
parent 69bca6a5
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -1195,7 +1195,12 @@ class ActivityStarter {
            }
        }

        // Only allow app switching to be resumed if activity is not a restricted background
        // activity, otherwise any background activity started in background task can stop
        // home button protection mode.
        if (!restrictedBgActivity) {
            mService.onStartActivitySetDidAppSwitch();
        }
        mController.doPendingActivityLaunches(false);

        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
@@ -1260,6 +1265,20 @@ class ActivityStarter {
            return false;
        }

        // Always allow home application to start activities.
        if (mService.mHomeProcess != null && callingUid == mService.mHomeProcess.mUid) {
            if (DEBUG_ACTIVITY_STARTS) {
                Slog.d(TAG, "Activity start allowed for home app callingUid (" + callingUid + ")");
            }
            return false;
        }

        // App switching will be allowed if BAL app switching flag is not enabled, or if
        // its app switching rule allows it.
        // This is used to block background activity launch even if the app is still
        // visible to user after user clicking home button.
        final boolean appSwitchAllowed = mService.getBalAppSwitchesAllowed();

        // don't abort if the callingUid has a visible window or is a persistent system process
        final int callingUidProcState = mService.getUidState(callingUid);
        final boolean callingUidHasAnyVisibleWindow =
@@ -1269,7 +1288,8 @@ class ActivityStarter {
                || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
        final boolean isCallingUidPersistentSystemProcess =
                callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
        if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) {
        if ((appSwitchAllowed && callingUidHasAnyVisibleWindow)
                || isCallingUidPersistentSystemProcess) {
            if (DEBUG_ACTIVITY_STARTS) {
                Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
                        + ", isCallingUidPersistentSystemProcess = "
@@ -1295,6 +1315,7 @@ class ActivityStarter {
                        || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
        if (realCallingUid != callingUid) {
            // 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
@@ -1376,7 +1397,7 @@ class ActivityStarter {
        // don't abort if the callerApp or other processes of that uid are allowed in any way
        if (callerApp != null) {
            // first check the original calling process
            if (callerApp.areBackgroundActivityStartsAllowed()) {
            if (callerApp.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
                if (DEBUG_ACTIVITY_STARTS) {
                    Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
                            + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
@@ -1389,7 +1410,8 @@ class ActivityStarter {
            if (uidProcesses != null) {
                for (int i = uidProcesses.size() - 1; i >= 0; i--) {
                    final WindowProcessController proc = uidProcesses.valueAt(i);
                    if (proc != callerApp && proc.areBackgroundActivityStartsAllowed()) {
                    if (proc != callerApp
                            && proc.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
                        if (DEBUG_ACTIVITY_STARTS) {
                            Slog.d(TAG,
                                    "Background activity start allowed: process " + proc.getPid()
+39 −1
Original line number Diff line number Diff line
@@ -160,9 +160,11 @@ import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyCache;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.compat.CompatChanges;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.EnterPipRequestedItem;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -341,6 +343,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
    /** This activity is being relaunched due to a free-resize operation. */
    public static final int RELAUNCH_REASON_FREE_RESIZE = 2;

    /**
     * Apps are blocked from starting activities in the foreground after the user presses home.
     */
    @ChangeId
    public static final long BLOCK_ACTIVITY_STARTS_AFTER_HOME = 159433730L;

    Context mContext;

    /**
@@ -2626,8 +2634,35 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
        throw new SecurityException(msg);
    }

    /**
     * Return true if app switch protection will be handled by background activity launch logic.
     */
    boolean getBalAppSwitchesProtectionEnabled() {
        return CompatChanges.isChangeEnabled(BLOCK_ACTIVITY_STARTS_AFTER_HOME);
    }

    /**
     * Return true if app switching is allowed.
     */
    boolean getBalAppSwitchesAllowed() {
        if (getBalAppSwitchesProtectionEnabled()) {
            // Apps no longer able to start BAL again until app switching is resumed.
            return mAppSwitchesAllowedTime == 0;
        } else {
            // Legacy behavior, BAL logic won't block app switching.
            return true;
        }
    }

    boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
            int callingPid, int callingUid, String name) {

        // Background activity launch logic replaces app switching protection, so allow
        // apps to start activity here now.
        if (getBalAppSwitchesProtectionEnabled()) {
            return true;
        }

        if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
            return true;
        }
@@ -4647,9 +4682,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
            mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME;
            mLastStopAppSwitchesTime = SystemClock.uptimeMillis();
            mDidAppSwitch = false;
            // If BAL app switching enabled, app switches are blocked not delayed.
            if (!getBalAppSwitchesProtectionEnabled()) {
                getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
            }
        }
    }

    @Override
    public void resumeAppSwitches() {
+25 −21
Original line number Diff line number Diff line
@@ -505,7 +505,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
        }
    }

    boolean areBackgroundActivityStartsAllowed() {
    boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed) {
        // 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 (appSwitchAllowed) {
            // 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.
            final long now = SystemClock.uptimeMillis();
@@ -529,6 +532,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
                }

            }
        }
        // allow if the proc is instrumenting with background activity starts privs
        if (mInstrumentingWithBackgroundActivityStartPrivileges) {
            if (DEBUG_ACTIVITY_STARTS) {
@@ -539,7 +543,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
            return true;
        }
        // allow if the caller has an activity in any foreground task
        if (hasActivityInVisibleTask()) {
        if (appSwitchAllowed && hasActivityInVisibleTask()) {
            if (DEBUG_ACTIVITY_STARTS) {
                Slog.d(TAG, "[WindowProcessController(" + mPid
                        + ")] Activity start allowed: process has activity in foreground task");