diff options
3 files changed, 90 insertions, 26 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 910a1a2c69b2..25b2523b1a3e 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1195,7 +1195,12 @@ class ActivityStarter { } } - mService.onStartActivitySetDidAppSwitch(); + // 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() diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index c582e6c8cb29..e102d68ecf35 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -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,7 +4682,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME; mLastStopAppSwitchesTime = SystemClock.uptimeMillis(); mDidAppSwitch = false; - getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME); + // If BAL app switching enabled, app switches are blocked not delayed. + if (!getBalAppSwitchesProtectionEnabled()) { + getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME); + } } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 2e7905c64049..2d69dcbcfbd0 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -505,29 +505,33 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } - boolean areBackgroundActivityStartsAllowed() { - // 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(); - if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS - || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) { - // if activity is started and finished before stop app switch time, we should not - // let app to be able to start background activity even it's in grace period. - if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime() - || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) { + 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(); + if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS + || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) { + // if activity is started and finished before stop app switch time, we should not + // let app to be able to start background activity even it's in grace period. + if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime() + || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) { + if (DEBUG_ACTIVITY_STARTS) { + Slog.d(TAG, "[WindowProcessController(" + mPid + + ")] Activity start allowed: within " + + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); + } + return true; + } if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[WindowProcessController(" + mPid - + ")] Activity start allowed: within " - + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); + Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within " + + ACTIVITY_BG_START_GRACE_PERIOD_MS + + "ms grace period but also within stop app switch window"); } - return true; - } - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within " - + ACTIVITY_BG_START_GRACE_PERIOD_MS - + "ms grace period but also within stop app switch window"); - } + } } // allow if the proc is instrumenting with background activity starts privs if (mInstrumentingWithBackgroundActivityStartPrivileges) { @@ -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"); |