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. This CL also fix gesture mode doesn't resume app switching bug. In the original logic, ActivityStarter will wait for 2nd activity to be started to resume app switching, which it won't be happened in gesture mode as it doesn't start launcher app in 1st activity. This feature is currently disabled by defaut and gated by device config. Bug: 159433730 Test: Create an app that startActivity in onPause(), then click home button or swipe to home screen. Activity can be started in its background task but not a new foreground task (Both gesture mode and 3 buttons navigation mode). Disable this feature and test again, app can start new foreground task this time. Test: Click home button / swipe to home screen and open bbc app from launcher, click on the videos in bbc app and able to start new activity (Both in gesture mode and 3 buttons launcher button). It should behave the same when this feature is enabled / disabled. Test: Create an app and enter pip mode in background and start new activity task. After pressing home button / wipe to home, apps can enter pip mode but cannot create a new task. Test again with this feature is being disabled, pip app should be still able to start foreground activity. Change-Id: Id514f5ee34ebc65001783174ae70e05a40757d11
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
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<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");
|
||||
|
||||
Reference in New Issue
Block a user