Loading services/core/java/com/android/server/pm/UserManagerService.java +4 −380 Original line number Original line Diff line number Diff line Loading @@ -33,7 +33,6 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.IActivityManager; import android.app.IActivityManager; import android.app.IStopUserCallback; import android.app.IStopUserCallback; import android.app.KeyguardManager; import android.app.KeyguardManager; Loading Loading @@ -80,7 +79,6 @@ import android.os.SELinux; import android.os.ServiceManager; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.ServiceSpecificException; import android.os.ShellCallback; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemClock; import android.os.SystemProperties; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; Loading Loading @@ -127,11 +125,9 @@ import com.android.server.BundleUtils; import com.android.server.LocalServices; import com.android.server.LocalServices; import com.android.server.LockGuard; import com.android.server.LockGuard; import com.android.server.SystemService; import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.am.UserState; import com.android.server.am.UserState; import com.android.server.pm.UserManagerInternal.UserLifecycleListener; import com.android.server.pm.UserManagerInternal.UserLifecycleListener; import com.android.server.pm.UserManagerInternal.UserRestrictionsListener; import com.android.server.pm.UserManagerInternal.UserRestrictionsListener; import com.android.server.power.ShutdownThread; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.utils.Slogf; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.utils.TimingsTraceAndSlog; Loading Loading @@ -1756,7 +1752,7 @@ public class UserManagerService extends IUserManager.Stub { // UserManagerInternal if needed by other components (like WindowManagerService) // UserManagerInternal if needed by other components (like WindowManagerService) // TODO(b/239982558): add unit test // TODO(b/239982558): add unit test // TODO(b/239982558): try to merge with isUserVisibleUnchecked() // TODO(b/239982558): try to merge with isUserVisibleUnchecked() private boolean isUserVisibleOnDisplay(@UserIdInt int userId, int displayId) { boolean isUserVisibleOnDisplay(@UserIdInt int userId, int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { if (displayId == Display.DEFAULT_DISPLAY) { return isCurrentUserOrRunningProfileOfCurrentUser(userId); return isCurrentUserOrRunningProfileOfCurrentUser(userId); } } Loading Loading @@ -5937,383 +5933,11 @@ public class UserManagerService extends IUserManager.Stub { public void onShellCommand(FileDescriptor in, FileDescriptor out, public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { ResultReceiver resultReceiver) { (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); (new UserManagerServiceShellCommand(this, mSystemPackageInstaller, mLockPatternUtils, mContext)) .exec(this, in, out, err, args, callback, resultReceiver); } } private final class Shell extends ShellCommand { @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); pw.println("User manager (user) commands:"); pw.println(" help"); pw.println(" Prints this help text."); pw.println(); pw.println(" list [-v | --verbose] [--all]"); pw.println(" Prints all users on the system."); pw.println(); pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] " + "[--critical-only] [--mode MODE]"); pw.println(" Reports all issues on user-type package allowlist XML files. Options:"); pw.println(" -v | --verbose: shows extra info, like number of issues"); pw.println(" --critical-only: show only critical issues, excluding warnings"); pw.println(" --mode MODE: shows what errors would be if device used mode MODE"); pw.println(" (where MODE is the allowlist mode integer as defined by " + "config_userTypePackageWhitelistMode)"); pw.println(); pw.println(" set-system-user-mode-emulation [--reboot | --no-restart] " + "<headless | full | default>"); pw.println(" Changes whether the system user is headless, full, or default (as " + "defined by OEM)."); pw.println(" WARNING: this command is meant just for development and debugging " + "purposes."); pw.println(" It should NEVER be used on automated tests."); pw.println(" NOTE: by default it restarts the Android runtime, unless called with"); pw.println(" --reboot (which does a full reboot) or"); pw.println(" --no-restart (which requires a manual restart)"); pw.println(); pw.println(" is-user-visible [--display DISPLAY_ID] <USER_ID>"); pw.println(" Checks if the given user is visible in the given display."); pw.println(" If the display option is not set, it uses the user's context to check"); pw.println(" (so it emulates what apps would get from UserManager.isUserVisible())"); pw.println(); } @Override public int onCommand(String cmd) { if (cmd == null) { return handleDefaultCommands(cmd); } try { switch(cmd) { case "list": return runList(); case "report-system-user-package-whitelist-problems": return runReportPackageAllowlistProblems(); case "set-system-user-mode-emulation": return runSetSystemUserModeEmulation(); case "is-user-visible": return runIsUserVisible(); default: return handleDefaultCommands(cmd); } } catch (RemoteException e) { getOutPrintWriter().println("Remote exception: " + e); } return -1; } private int runList() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); boolean all = false; boolean verbose = false; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-v": case "--verbose": verbose = true; break; case "--all": all = true; break; default: pw.println("Invalid option: " + opt); return -1; } } final IActivityManager am = ActivityManager.getService(); final List<UserInfo> users = getUsers(/* excludePartial= */ !all, /* excludeDying= */ false, /* excludePreCreated= */ !all); if (users == null) { pw.println("Error: couldn't get users"); return 1; } else { final int size = users.size(); int currentUser = UserHandle.USER_NULL; if (verbose) { pw.printf("%d users:\n\n", size); currentUser = am.getCurrentUser().id; } else { // NOTE: the standard "list users" command is used by integration tests and // hence should not be changed. If you need to add more info, use the // verbose option. pw.println("Users:"); } for (int i = 0; i < size; i++) { final UserInfo user = users.get(i); final boolean running = am.isUserRunning(user.id, 0); if (verbose) { final DevicePolicyManagerInternal dpm = getDevicePolicyManagerInternal(); String deviceOwner = ""; String profileOwner = ""; if (dpm != null) { final long ident = Binder.clearCallingIdentity(); // NOTE: dpm methods below CANNOT be called while holding the mUsersLock try { if (dpm.getDeviceOwnerUserId() == user.id) { deviceOwner = " (device-owner)"; } if (dpm.getProfileOwnerAsUser(user.id) != null) { profileOwner = " (profile-owner)"; } } finally { Binder.restoreCallingIdentity(ident); } } final boolean current = user.id == currentUser; final boolean hasParent = user.profileGroupId != user.id && user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID; final boolean visible = isUserVisibleUnchecked(user.id); pw.printf("%d: id=%d, name=%s, type=%s, flags=%s%s%s%s%s%s%s%s%s%s\n", i, user.id, user.name, user.userType.replace("android.os.usertype.", ""), UserInfo.flagsToString(user.flags), hasParent ? " (parentId=" + user.profileGroupId + ")" : "", running ? " (running)" : "", user.partial ? " (partial)" : "", user.preCreated ? " (pre-created)" : "", user.convertedFromPreCreated ? " (converted)" : "", deviceOwner, profileOwner, current ? " (current)" : "", visible ? " (visible)" : "" ); } else { // NOTE: the standard "list users" command is used by integration tests and // hence should not be changed. If you need to add more info, use the // verbose option. pw.printf("\t%s%s\n", user, running ? " running" : ""); } } return 0; } } private int runReportPackageAllowlistProblems() { final PrintWriter pw = getOutPrintWriter(); boolean verbose = false; boolean criticalOnly = false; int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-v": case "--verbose": verbose = true; break; case "--critical-only": criticalOnly = true; break; case "--mode": mode = Integer.parseInt(getNextArgRequired()); break; default: pw.println("Invalid option: " + opt); return -1; } } Slog.d(LOG_TAG, "runReportPackageAllowlistProblems(): verbose=" + verbose + ", criticalOnly=" + criticalOnly + ", mode=" + UserSystemPackageInstaller.modeToString(mode)); try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) { mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly); } return 0; } private int runSetSystemUserModeEmulation() { if (!confirmBuildIsDebuggable() || !confirmIsCalledByRoot()) { return -1; } final PrintWriter pw = getOutPrintWriter(); // The headless system user cannot be locked; in theory, we could just make this check // when going full -> headless, but it doesn't hurt to check on both (and it makes the // code simpler) if (mLockPatternUtils.isSecure(UserHandle.USER_SYSTEM)) { pw.println("Cannot change system user mode when it has a credential"); return -1; } boolean restart = true; boolean reboot = false; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "--reboot": reboot = true; break; case "--no-restart": restart = false; break; default: pw.println("Invalid option: " + opt); return -1; } } if (reboot && !restart) { getErrPrintWriter().println("You can use --reboot or --no-restart, but not both"); return -1; } final String mode = getNextArgRequired(); final boolean isHeadlessSystemUserModeCurrently = UserManager .isHeadlessSystemUserMode(); final boolean changed; switch (mode) { case UserManager.SYSTEM_USER_MODE_EMULATION_FULL: changed = isHeadlessSystemUserModeCurrently; break; case UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS: changed = !isHeadlessSystemUserModeCurrently; break; case UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT: changed = true; // Always update when resetting to default break; default: getErrPrintWriter().printf("Invalid arg: %s\n", mode); return -1; } if (!changed) { pw.printf("No change needed, system user is already %s\n", isHeadlessSystemUserModeCurrently ? "headless" : "full"); return 0; } Slogf.d(LOG_TAG, "Updating system property %s to %s", UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, mode); SystemProperties.set(UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, mode); if (reboot) { Slog.i(LOG_TAG, "Rebooting to finalize the changes"); pw.println("Rebooting to finalize changes"); UiThread.getHandler() .post(() -> ShutdownThread.reboot( ActivityThread.currentActivityThread().getSystemUiContext(), "To switch headless / full system user mode", /* confirm= */ false)); } else if (restart) { Slog.i(LOG_TAG, "Shutting PackageManager down"); getPackageManagerInternal().shutdown(); final IActivityManager am = ActivityManager.getService(); if (am != null) { try { Slog.i(LOG_TAG, "Shutting ActivityManager down"); am.shutdown(/* timeout= */ 10_000); } catch (RemoteException e) { } } final int pid = Process.myPid(); Slogf.i(LOG_TAG, "Restarting Android runtime(PID=%d) to finalize changes", pid); pw.println("Restarting Android runtime to finalize changes"); pw.flush(); // Ideally there should be a cleaner / safer option to restart system_server, but // that doesn't seems to be the case. For example, ShutdownThread.reboot() calls // pm.shutdown() and am.shutdown() (which we already are calling above), but when // the system is restarted through 'adb shell stop && adb shell start`, these // methods are not called, so just killing the process seems to be fine. Process.killProcess(pid); } else { pw.println("System user mode changed - please reboot (or restart Android runtime) " + "to continue"); pw.println("NOTICE: after restart, some apps might be uninstalled (and their data " + "will be lost)"); } return 0; } private int runIsUserVisible() { PrintWriter pw = getOutPrintWriter(); int displayId = Display.INVALID_DISPLAY; String opt; while ((opt = getNextOption()) != null) { boolean invalidOption = false; switch (opt) { case "--display": displayId = Integer.parseInt(getNextArgRequired()); invalidOption = displayId == Display.INVALID_DISPLAY; break; default: invalidOption = true; } if (invalidOption) { pw.println("Invalid option: " + opt); return -1; } } int userId = UserHandle.parseUserArg(getNextArgRequired()); switch (userId) { case UserHandle.USER_ALL: case UserHandle.USER_CURRENT_OR_SELF: case UserHandle.USER_NULL: pw.printf("invalid value (%d) for --user option\n", userId); return -1; case UserHandle.USER_CURRENT: userId = ActivityManager.getCurrentUser(); break; } boolean isVisible; if (displayId != Display.INVALID_DISPLAY) { isVisible = isUserVisibleOnDisplay(userId, displayId); } else { isVisible = getUserManagerForUser(userId).isUserVisible(); } pw.println(isVisible); return 0; } /** * Gets the {@link UserManager} associated with the context of the given user. */ private UserManager getUserManagerForUser(int userId) { UserHandle user = UserHandle.of(userId); Context context = mContext.createContextAsUser(user, /* flags= */ 0); return context.getSystemService(UserManager.class); } /** * Confirms if the build is debuggable * * <p>It logs an error when it isn't. */ private boolean confirmBuildIsDebuggable() { if (Build.isDebuggable()) { return true; } getErrPrintWriter().println("Command not available on user builds"); return false; } /** * Confirms if the command is called when {@code adb} is rooted. * * <p>It logs an error when it isn't. */ private boolean confirmIsCalledByRoot() { if (Binder.getCallingUid() == Process.ROOT_UID) { return true; } getErrPrintWriter().println("Command only available on root user"); return false; } } // class Shell @Override @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; Loading services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java 0 → 100644 +450 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/pm/UserManagerService.java +4 −380 Original line number Original line Diff line number Diff line Loading @@ -33,7 +33,6 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.IActivityManager; import android.app.IActivityManager; import android.app.IStopUserCallback; import android.app.IStopUserCallback; import android.app.KeyguardManager; import android.app.KeyguardManager; Loading Loading @@ -80,7 +79,6 @@ import android.os.SELinux; import android.os.ServiceManager; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.ServiceSpecificException; import android.os.ShellCallback; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemClock; import android.os.SystemProperties; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; Loading Loading @@ -127,11 +125,9 @@ import com.android.server.BundleUtils; import com.android.server.LocalServices; import com.android.server.LocalServices; import com.android.server.LockGuard; import com.android.server.LockGuard; import com.android.server.SystemService; import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.am.UserState; import com.android.server.am.UserState; import com.android.server.pm.UserManagerInternal.UserLifecycleListener; import com.android.server.pm.UserManagerInternal.UserLifecycleListener; import com.android.server.pm.UserManagerInternal.UserRestrictionsListener; import com.android.server.pm.UserManagerInternal.UserRestrictionsListener; import com.android.server.power.ShutdownThread; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.utils.Slogf; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.utils.TimingsTraceAndSlog; Loading Loading @@ -1756,7 +1752,7 @@ public class UserManagerService extends IUserManager.Stub { // UserManagerInternal if needed by other components (like WindowManagerService) // UserManagerInternal if needed by other components (like WindowManagerService) // TODO(b/239982558): add unit test // TODO(b/239982558): add unit test // TODO(b/239982558): try to merge with isUserVisibleUnchecked() // TODO(b/239982558): try to merge with isUserVisibleUnchecked() private boolean isUserVisibleOnDisplay(@UserIdInt int userId, int displayId) { boolean isUserVisibleOnDisplay(@UserIdInt int userId, int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { if (displayId == Display.DEFAULT_DISPLAY) { return isCurrentUserOrRunningProfileOfCurrentUser(userId); return isCurrentUserOrRunningProfileOfCurrentUser(userId); } } Loading Loading @@ -5937,383 +5933,11 @@ public class UserManagerService extends IUserManager.Stub { public void onShellCommand(FileDescriptor in, FileDescriptor out, public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { ResultReceiver resultReceiver) { (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); (new UserManagerServiceShellCommand(this, mSystemPackageInstaller, mLockPatternUtils, mContext)) .exec(this, in, out, err, args, callback, resultReceiver); } } private final class Shell extends ShellCommand { @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); pw.println("User manager (user) commands:"); pw.println(" help"); pw.println(" Prints this help text."); pw.println(); pw.println(" list [-v | --verbose] [--all]"); pw.println(" Prints all users on the system."); pw.println(); pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] " + "[--critical-only] [--mode MODE]"); pw.println(" Reports all issues on user-type package allowlist XML files. Options:"); pw.println(" -v | --verbose: shows extra info, like number of issues"); pw.println(" --critical-only: show only critical issues, excluding warnings"); pw.println(" --mode MODE: shows what errors would be if device used mode MODE"); pw.println(" (where MODE is the allowlist mode integer as defined by " + "config_userTypePackageWhitelistMode)"); pw.println(); pw.println(" set-system-user-mode-emulation [--reboot | --no-restart] " + "<headless | full | default>"); pw.println(" Changes whether the system user is headless, full, or default (as " + "defined by OEM)."); pw.println(" WARNING: this command is meant just for development and debugging " + "purposes."); pw.println(" It should NEVER be used on automated tests."); pw.println(" NOTE: by default it restarts the Android runtime, unless called with"); pw.println(" --reboot (which does a full reboot) or"); pw.println(" --no-restart (which requires a manual restart)"); pw.println(); pw.println(" is-user-visible [--display DISPLAY_ID] <USER_ID>"); pw.println(" Checks if the given user is visible in the given display."); pw.println(" If the display option is not set, it uses the user's context to check"); pw.println(" (so it emulates what apps would get from UserManager.isUserVisible())"); pw.println(); } @Override public int onCommand(String cmd) { if (cmd == null) { return handleDefaultCommands(cmd); } try { switch(cmd) { case "list": return runList(); case "report-system-user-package-whitelist-problems": return runReportPackageAllowlistProblems(); case "set-system-user-mode-emulation": return runSetSystemUserModeEmulation(); case "is-user-visible": return runIsUserVisible(); default: return handleDefaultCommands(cmd); } } catch (RemoteException e) { getOutPrintWriter().println("Remote exception: " + e); } return -1; } private int runList() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); boolean all = false; boolean verbose = false; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-v": case "--verbose": verbose = true; break; case "--all": all = true; break; default: pw.println("Invalid option: " + opt); return -1; } } final IActivityManager am = ActivityManager.getService(); final List<UserInfo> users = getUsers(/* excludePartial= */ !all, /* excludeDying= */ false, /* excludePreCreated= */ !all); if (users == null) { pw.println("Error: couldn't get users"); return 1; } else { final int size = users.size(); int currentUser = UserHandle.USER_NULL; if (verbose) { pw.printf("%d users:\n\n", size); currentUser = am.getCurrentUser().id; } else { // NOTE: the standard "list users" command is used by integration tests and // hence should not be changed. If you need to add more info, use the // verbose option. pw.println("Users:"); } for (int i = 0; i < size; i++) { final UserInfo user = users.get(i); final boolean running = am.isUserRunning(user.id, 0); if (verbose) { final DevicePolicyManagerInternal dpm = getDevicePolicyManagerInternal(); String deviceOwner = ""; String profileOwner = ""; if (dpm != null) { final long ident = Binder.clearCallingIdentity(); // NOTE: dpm methods below CANNOT be called while holding the mUsersLock try { if (dpm.getDeviceOwnerUserId() == user.id) { deviceOwner = " (device-owner)"; } if (dpm.getProfileOwnerAsUser(user.id) != null) { profileOwner = " (profile-owner)"; } } finally { Binder.restoreCallingIdentity(ident); } } final boolean current = user.id == currentUser; final boolean hasParent = user.profileGroupId != user.id && user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID; final boolean visible = isUserVisibleUnchecked(user.id); pw.printf("%d: id=%d, name=%s, type=%s, flags=%s%s%s%s%s%s%s%s%s%s\n", i, user.id, user.name, user.userType.replace("android.os.usertype.", ""), UserInfo.flagsToString(user.flags), hasParent ? " (parentId=" + user.profileGroupId + ")" : "", running ? " (running)" : "", user.partial ? " (partial)" : "", user.preCreated ? " (pre-created)" : "", user.convertedFromPreCreated ? " (converted)" : "", deviceOwner, profileOwner, current ? " (current)" : "", visible ? " (visible)" : "" ); } else { // NOTE: the standard "list users" command is used by integration tests and // hence should not be changed. If you need to add more info, use the // verbose option. pw.printf("\t%s%s\n", user, running ? " running" : ""); } } return 0; } } private int runReportPackageAllowlistProblems() { final PrintWriter pw = getOutPrintWriter(); boolean verbose = false; boolean criticalOnly = false; int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-v": case "--verbose": verbose = true; break; case "--critical-only": criticalOnly = true; break; case "--mode": mode = Integer.parseInt(getNextArgRequired()); break; default: pw.println("Invalid option: " + opt); return -1; } } Slog.d(LOG_TAG, "runReportPackageAllowlistProblems(): verbose=" + verbose + ", criticalOnly=" + criticalOnly + ", mode=" + UserSystemPackageInstaller.modeToString(mode)); try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) { mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly); } return 0; } private int runSetSystemUserModeEmulation() { if (!confirmBuildIsDebuggable() || !confirmIsCalledByRoot()) { return -1; } final PrintWriter pw = getOutPrintWriter(); // The headless system user cannot be locked; in theory, we could just make this check // when going full -> headless, but it doesn't hurt to check on both (and it makes the // code simpler) if (mLockPatternUtils.isSecure(UserHandle.USER_SYSTEM)) { pw.println("Cannot change system user mode when it has a credential"); return -1; } boolean restart = true; boolean reboot = false; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "--reboot": reboot = true; break; case "--no-restart": restart = false; break; default: pw.println("Invalid option: " + opt); return -1; } } if (reboot && !restart) { getErrPrintWriter().println("You can use --reboot or --no-restart, but not both"); return -1; } final String mode = getNextArgRequired(); final boolean isHeadlessSystemUserModeCurrently = UserManager .isHeadlessSystemUserMode(); final boolean changed; switch (mode) { case UserManager.SYSTEM_USER_MODE_EMULATION_FULL: changed = isHeadlessSystemUserModeCurrently; break; case UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS: changed = !isHeadlessSystemUserModeCurrently; break; case UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT: changed = true; // Always update when resetting to default break; default: getErrPrintWriter().printf("Invalid arg: %s\n", mode); return -1; } if (!changed) { pw.printf("No change needed, system user is already %s\n", isHeadlessSystemUserModeCurrently ? "headless" : "full"); return 0; } Slogf.d(LOG_TAG, "Updating system property %s to %s", UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, mode); SystemProperties.set(UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, mode); if (reboot) { Slog.i(LOG_TAG, "Rebooting to finalize the changes"); pw.println("Rebooting to finalize changes"); UiThread.getHandler() .post(() -> ShutdownThread.reboot( ActivityThread.currentActivityThread().getSystemUiContext(), "To switch headless / full system user mode", /* confirm= */ false)); } else if (restart) { Slog.i(LOG_TAG, "Shutting PackageManager down"); getPackageManagerInternal().shutdown(); final IActivityManager am = ActivityManager.getService(); if (am != null) { try { Slog.i(LOG_TAG, "Shutting ActivityManager down"); am.shutdown(/* timeout= */ 10_000); } catch (RemoteException e) { } } final int pid = Process.myPid(); Slogf.i(LOG_TAG, "Restarting Android runtime(PID=%d) to finalize changes", pid); pw.println("Restarting Android runtime to finalize changes"); pw.flush(); // Ideally there should be a cleaner / safer option to restart system_server, but // that doesn't seems to be the case. For example, ShutdownThread.reboot() calls // pm.shutdown() and am.shutdown() (which we already are calling above), but when // the system is restarted through 'adb shell stop && adb shell start`, these // methods are not called, so just killing the process seems to be fine. Process.killProcess(pid); } else { pw.println("System user mode changed - please reboot (or restart Android runtime) " + "to continue"); pw.println("NOTICE: after restart, some apps might be uninstalled (and their data " + "will be lost)"); } return 0; } private int runIsUserVisible() { PrintWriter pw = getOutPrintWriter(); int displayId = Display.INVALID_DISPLAY; String opt; while ((opt = getNextOption()) != null) { boolean invalidOption = false; switch (opt) { case "--display": displayId = Integer.parseInt(getNextArgRequired()); invalidOption = displayId == Display.INVALID_DISPLAY; break; default: invalidOption = true; } if (invalidOption) { pw.println("Invalid option: " + opt); return -1; } } int userId = UserHandle.parseUserArg(getNextArgRequired()); switch (userId) { case UserHandle.USER_ALL: case UserHandle.USER_CURRENT_OR_SELF: case UserHandle.USER_NULL: pw.printf("invalid value (%d) for --user option\n", userId); return -1; case UserHandle.USER_CURRENT: userId = ActivityManager.getCurrentUser(); break; } boolean isVisible; if (displayId != Display.INVALID_DISPLAY) { isVisible = isUserVisibleOnDisplay(userId, displayId); } else { isVisible = getUserManagerForUser(userId).isUserVisible(); } pw.println(isVisible); return 0; } /** * Gets the {@link UserManager} associated with the context of the given user. */ private UserManager getUserManagerForUser(int userId) { UserHandle user = UserHandle.of(userId); Context context = mContext.createContextAsUser(user, /* flags= */ 0); return context.getSystemService(UserManager.class); } /** * Confirms if the build is debuggable * * <p>It logs an error when it isn't. */ private boolean confirmBuildIsDebuggable() { if (Build.isDebuggable()) { return true; } getErrPrintWriter().println("Command not available on user builds"); return false; } /** * Confirms if the command is called when {@code adb} is rooted. * * <p>It logs an error when it isn't. */ private boolean confirmIsCalledByRoot() { if (Binder.getCallingUid() == Process.ROOT_UID) { return true; } getErrPrintWriter().println("Command only available on root user"); return false; } } // class Shell @Override @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; Loading
services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java 0 → 100644 +450 −0 File added.Preview size limit exceeded, changes collapsed. Show changes