diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 910a1a2c69b2e..a3ae86276fd08 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1195,7 +1195,23 @@ class ActivityStarter { } } - mService.onStartActivitySetDidAppSwitch(); + if (mService.getBalAppSwitchesProtectionEnabled()) { + // Only allow app switching to be resumed if activity is not a restricted background + // activity and target app is not home process, otherwise any background activity + // started in background task can stop home button protection mode. + // As the targeted app is not a home process and we don't need to wait for the 2nd + // activity to be started to resume app switching, we can just enable app switching + // directly. + WindowProcessController homeProcess = mService.mHomeProcess; + boolean isHomeProcess = homeProcess != null + && aInfo.applicationInfo.uid == homeProcess.mUid; + if (!restrictedBgActivity && !isHomeProcess) { + mService.resumeAppSwitches(); + } + } else { + mService.onStartActivitySetDidAppSwitch(); + } + mController.doPendingActivityLaunches(false); mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, @@ -1260,6 +1276,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 +1299,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 +1326,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 +1408,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 +1421,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() @@ -1403,6 +1436,8 @@ class ActivityStarter { // anything that has fallen through would currently be aborted Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage + "; callingUid: " + callingUid + + "; appSwitchAllowed: " + appSwitchAllowed + + "; balAppSwitchEnabled: " + mService.getBalAppSwitchesProtectionEnabled() + "; isCallingUidForeground: " + isCallingUidForeground + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow + "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 46bf5ad224ad2..55d2784ac8b59 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -161,9 +161,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; @@ -214,6 +216,7 @@ import android.os.UserManager; import android.os.WorkSource; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.service.dreams.DreamActivity; import android.service.voice.IVoiceInteractionSession; @@ -342,6 +345,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. + */ + public static final String BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG = + "am_block_activity_starts_after_home"; + Context mContext; /** @@ -394,6 +403,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { volatile WindowProcessController mHeavyWeightProcess; boolean mHasHeavyWeightFeature; boolean mHasLeanbackFeature; + boolean mBlockActivityAfterHomeEnabled; /** The process of the top most activity. */ volatile WindowProcessController mTopApp; /** @@ -756,6 +766,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mVrController.onSystemReady(); mRecentTasks.onSystemReadyLocked(); mStackSupervisor.onSystemReady(); + mBlockActivityAfterHomeEnabled = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG, false); } } @@ -2627,8 +2640,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 mBlockActivityAfterHomeEnabled; + } + + /** + * 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; } @@ -4663,7 +4703,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 2e7905c64049e..2d69dcbcfbd02 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 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"); + 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 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