New TestAPIs on ActivityManager to not stop bg users on switch.
Test: atest NeneTest:UsersTest
Test: m update-api
Test: adb shell cmd activity set-stop-user-on-switch false
Test: adb shell cmd activity set-stop-user-on-switch
Test: adb shell dumpsys activity users|grep OnSwitch
Bug: 203752848
Change-Id: Ib57989aff323dc1f7d98720d01215e4f7c79ba3a
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 488f8b1..40880c1 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -113,6 +113,7 @@
method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setStopBackgroundUsersOnSwitch(int);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean);
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle();
@@ -127,6 +128,9 @@
field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
field public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; // 0x4
field public static final int PROCESS_STATE_TOP = 2; // 0x2
+ field public static final int STOP_BG_USERS_ON_SWITCH_DEFAULT = -1; // 0xffffffff
+ field public static final int STOP_BG_USERS_ON_SWITCH_FALSE = 0; // 0x0
+ field public static final int STOP_BG_USERS_ON_SWITCH_TRUE = 1; // 0x1
}
public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f53c5b6..50a562b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4076,6 +4076,56 @@
}
/**
+ * Uses the value defined by the platform.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_BG_USERS_ON_SWITCH_DEFAULT = -1;
+
+ /**
+ * Overrides value defined by the platform and stop background users on switch.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_BG_USERS_ON_SWITCH_TRUE = 1;
+
+ /**
+ * Overrides value defined by the platform and don't stop background users on switch.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_BG_USERS_ON_SWITCH_FALSE = 0;
+
+ /** @hide */
+ @IntDef(prefix = { "STOP_BG_USERS_ON_SWITCH_" }, value = {
+ STOP_BG_USERS_ON_SWITCH_DEFAULT,
+ STOP_BG_USERS_ON_SWITCH_TRUE,
+ STOP_BG_USERS_ON_SWITCH_FALSE
+ })
+ public @interface StopBgUsersOnSwitch {}
+
+ /**
+ * Sets whether background users should be stopped when the current user is switched.
+ *
+ * <p>Should only be used on tests.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ public void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ try {
+ getService().setStopBackgroundUsersOnSwitch(value);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Starts a profile.
* To be used with non-managed profiles, managed profiles should use
* {@link UserManager#requestQuietModeEnabled}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f8c8aa3..b416c95 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.app.ActivityManager.StopBgUsersOnSwitch;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -661,6 +663,11 @@
@Nullable VoiceInteractionManagerProvider provider);
/**
+ * Sets whether background users should be stopped when the current user is switched.
+ */
+ public abstract void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value);
+
+ /**
* Provides the interface to communicate between voice interaction manager service and
* ActivityManagerService.
*/
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b90b9a1..601ec9a 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -341,6 +341,7 @@
@UnsupportedAppUsage
boolean switchUser(int userid);
@UnsupportedAppUsage
+ void setStopBackgroundUsersOnSwitch(int value);
boolean removeTask(int taskId);
@UnsupportedAppUsage
void registerProcessObserver(in IProcessObserver observer);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 18ed958..36dcc8d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -31,6 +31,7 @@
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.app.ActivityManager.StopBgUsersOnSwitch;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.AppOpsManager.OP_NONE;
@@ -15096,6 +15097,11 @@
}
@Override
+ public void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ mUserController.setStopBackgroundUsersOnSwitch(value);
+ }
+
+ @Override
public int stopUser(final int userId, boolean force, final IStopUserCallback callback) {
return mUserController.stopUser(userId, force, /* allowDelayedLocking= */ false,
/* callback= */ callback, /* keyEvictedCallback= */ null);
@@ -16392,6 +16398,11 @@
@Nullable ActivityManagerInternal.VoiceInteractionManagerProvider provider) {
ActivityManagerService.this.setVoiceInteractionManagerProvider(provider);
}
+
+ @Override
+ public void setStopBackgroundUsersOnSwitch(int value) {
+ ActivityManagerService.this.setStopBackgroundUsersOnSwitch(value);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 685d606..60b2149 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -29,6 +29,8 @@
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;
import android.app.ActivityManager;
@@ -100,6 +102,7 @@
import com.android.internal.util.MemInfoReader;
import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.compat.PlatformCompat;
+import com.android.server.utils.Slogf;
import java.io.BufferedReader;
import java.io.IOException;
@@ -128,6 +131,10 @@
import javax.microedition.khronos.egl.EGLSurface;
final class ActivityManagerShellCommand extends ShellCommand {
+
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerShellCommand" : TAG_AM;
+
+
public static final String NO_CLASS_ERROR_CODE = "Error type 3";
private static final String SHELL_PACKAGE_NAME = "com.android.shell";
@@ -323,6 +330,8 @@
return runServiceRestartBackoff(pw);
case "get-isolated-pids":
return runGetIsolatedProcesses(pw);
+ case "set-stop-user-on-switch":
+ return runSetStopBackgroundUsersOnSwitch(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -3157,6 +3166,30 @@
return 0;
}
+ private int runSetStopBackgroundUsersOnSwitch(PrintWriter pw) throws RemoteException {
+ mInternal.enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "setStopBackgroundUsersOnSwitch()");
+ String arg = getNextArg();
+ if (arg == null) {
+ Slogf.i(TAG, "runSetStopBackgroundUsersOnSwitch(): resetting to default value");
+ mInternal.setStopBackgroundUsersOnSwitch(
+ ActivityManager.STOP_BG_USERS_ON_SWITCH_DEFAULT);
+ pw.println("Reset to default value");
+ return 0;
+ }
+
+ boolean stop = Boolean.parseBoolean(arg);
+ int value = stop
+ ? ActivityManager.STOP_BG_USERS_ON_SWITCH_TRUE
+ : ActivityManager.STOP_BG_USERS_ON_SWITCH_FALSE;
+
+ Slogf.i(TAG, "runSetStopBackgroundUsersOnSwitch(): setting to %d (%b)", value, stop);
+ mInternal.setStopBackgroundUsersOnSwitch(value);
+ pw.println("Set to " + stop);
+
+ return 0;
+ }
+
private Resources getResources(PrintWriter pw) throws RemoteException {
// system resources does not contain all the device configuration, construct it manually.
Configuration config = mInterface.getConfiguration();
@@ -3489,6 +3522,10 @@
pw.println(" Shows the restart backoff policy state for <PACKAGE_NAME>.");
pw.println(" get-isolated-pids <UID>");
pw.println(" Get the PIDs of isolated processes with packages in this <UID>");
+ pw.println(" set-stop-user-on-switch [true|false]");
+ pw.println(" Sets whether the current user (and its profiles) should be stopped"
+ + " when switching to a different user.");
+ pw.println(" Without arguments, it resets to the value defined by platform.");
pw.println();
Intent.printIntentArgsHelp(pw, "");
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ba3e1fb..b8be6c5 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -19,6 +19,9 @@
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.STOP_BG_USERS_ON_SWITCH_DEFAULT;
+import static android.app.ActivityManager.STOP_BG_USERS_ON_SWITCH_TRUE;
+import static android.app.ActivityManager.StopBgUsersOnSwitch;
import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
@@ -368,6 +371,13 @@
@GuardedBy("mLock")
private boolean mInitialized;
+ /**
+ * Defines the behavior of whether the background users should be stopped when the foreground
+ * user is switched.
+ */
+ @GuardedBy("mLock")
+ private @StopBgUsersOnSwitch int mStopBgUsersOnSwitch = STOP_BG_USERS_ON_SWITCH_DEFAULT;
+
UserController(ActivityManagerService service) {
this(new Injector(service));
}
@@ -408,8 +418,33 @@
}
}
+ void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
+ == PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ == PackageManager.PERMISSION_DENIED) {
+ throw new SecurityException(
+ "You either need MANAGE_USERS or INTERACT_ACROSS_USERS_FULL permission to "
+ + "call setStopBackgroundUsersOnSwitch()");
+ }
+
+ synchronized (mLock) {
+ Slogf.i(TAG, "setStopBackgroundUsersOnSwitch(): %d -> %d",
+ mStopBgUsersOnSwitch, value);
+ mStopBgUsersOnSwitch = value;
+ }
+ }
+
private boolean shouldStopBackgroundUsersOnSwitch() {
- int property = SystemProperties.getInt("fw.stop_bg_users_on_switch", -1);
+ synchronized (mLock) {
+ if (mStopBgUsersOnSwitch != STOP_BG_USERS_ON_SWITCH_DEFAULT) {
+ final boolean value = mStopBgUsersOnSwitch == STOP_BG_USERS_ON_SWITCH_TRUE;
+ Slogf.i(TAG, "isStopBackgroundUsersOnSwitch(): returning overridden value (%b)",
+ value);
+ return value;
+ }
+ }
+ final int property = SystemProperties.getInt("fw.stop_bg_users_on_switch", -1);
return property == -1 ? mDelayUserDataLocking : property == 1;
}
@@ -2611,8 +2646,9 @@
pw.println(" mTargetUserId:" + mTargetUserId);
pw.println(" mLastActiveUsers:" + mLastActiveUsers);
pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking);
- pw.println(" shouldStopBackgroundUsersOnSwitch:"
+ pw.println(" shouldStopBackgroundUsersOnSwitch():"
+ shouldStopBackgroundUsersOnSwitch());
+ pw.println(" mStopBgUsersOnSwitch:" + mStopBgUsersOnSwitch);
pw.println(" mMaxRunningUsers:" + mMaxRunningUsers);
pw.println(" mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
pw.println(" mInitialized:" + mInitialized);