Loading core/java/android/app/IActivityManager.aidl +11 −0 Original line number Original line Diff line number Diff line Loading @@ -760,4 +760,15 @@ interface IActivityManager { * </p> * </p> */ */ int getBackgroundRestrictionExemptionReason(int uid); int getBackgroundRestrictionExemptionReason(int uid); // Start (?) of T transactions /** * Similar to {@link #startUserInBackgroundWithListener(int userId, IProgressListener unlockProgressListener), * but setting the user as the visible user of that display (i.e., allowing the user and its * running profiles to launch activities on that display). * * <p>Typically used only by automotive builds when the vehicle has multiple displays. */ boolean startUserInBackgroundOnSecondaryDisplay(int userid, int displayId, IProgressListener unlockProgressListener); } } services/core/java/com/android/server/am/ActivityManagerService.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -16201,6 +16201,13 @@ public class ActivityManagerService extends IActivityManager.Stub return mUserController.startUser(userId, /* foreground */ true, unlockListener); return mUserController.startUser(userId, /* foreground */ true, unlockListener); } } @Override public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId, @Nullable IProgressListener unlockListener) { // Permission check done inside UserController. return mUserController.startUserOnSecondaryDisplay(userId, displayId, unlockListener); } /** /** * Unlocks the given user. * Unlocks the given user. * * services/core/java/com/android/server/am/ActivityManagerShellCommand.java +38 −13 Original line number Original line Diff line number Diff line Loading @@ -892,6 +892,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } } } } // TODO(b/239982558): might need to support --displayId as well private int runProfile(PrintWriter pw) throws RemoteException { private int runProfile(PrintWriter pw) throws RemoteException { final PrintWriter err = getErrPrintWriter(); final PrintWriter err = getErrPrintWriter(); String profileFile = null; String profileFile = null; Loading Loading @@ -2034,10 +2035,16 @@ final class ActivityManagerShellCommand extends ShellCommand { int runStartUser(PrintWriter pw) throws RemoteException { int runStartUser(PrintWriter pw) throws RemoteException { boolean wait = false; boolean wait = false; String opt; String opt; int displayId = Display.INVALID_DISPLAY; while ((opt = getNextOption()) != null) { while ((opt = getNextOption()) != null) { if ("-w".equals(opt)) { switch(opt) { case "-w": wait = true; wait = true; } else { break; case "--display": displayId = getDisplayIdFromNextArg(); break; default: getErrPrintWriter().println("Error: unknown option: " + opt); getErrPrintWriter().println("Error: unknown option: " + opt); return -1; return -1; } } Loading @@ -2045,15 +2052,25 @@ final class ActivityManagerShellCommand extends ShellCommand { int userId = Integer.parseInt(getNextArgRequired()); int userId = Integer.parseInt(getNextArgRequired()); final ProgressWaiter waiter = wait ? new ProgressWaiter() : null; final ProgressWaiter waiter = wait ? new ProgressWaiter() : null; boolean success = mInterface.startUserInBackgroundWithListener(userId, waiter); boolean success; String displaySuffix; if (displayId == Display.INVALID_DISPLAY) { success = mInterface.startUserInBackgroundWithListener(userId, waiter); displaySuffix = ""; } else { success = mInterface.startUserInBackgroundOnSecondaryDisplay(userId, displayId, waiter); displaySuffix = " on display " + displayId; } if (wait && success) { if (wait && success) { success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS); success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS); } } if (success) { if (success) { pw.println("Success: user started"); pw.println("Success: user started" + displaySuffix); } else { } else { getErrPrintWriter().println("Error: could not start user"); getErrPrintWriter().println("Error: could not start user" + displaySuffix); } } return 0; return 0; } } Loading Loading @@ -2506,6 +2523,14 @@ final class ActivityManagerShellCommand extends ShellCommand { } } } } private int getDisplayIdFromNextArg() { int displayId = Integer.parseInt(getNextArgRequired()); if (displayId < 0) { throw new IllegalArgumentException("--display must be a non-negative integer"); } return displayId; } int runGetConfig(PrintWriter pw) throws RemoteException { int runGetConfig(PrintWriter pw) throws RemoteException { int days = -1; int days = -1; int displayId = Display.DEFAULT_DISPLAY; int displayId = Display.DEFAULT_DISPLAY; Loading @@ -2524,10 +2549,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } else if (opt.equals("--device")) { } else if (opt.equals("--device")) { inclDevice = true; inclDevice = true; } else if (opt.equals("--display")) { } else if (opt.equals("--display")) { displayId = Integer.parseInt(getNextArgRequired()); displayId = getDisplayIdFromNextArg(); if (displayId < 0) { throw new IllegalArgumentException("--display must be a non-negative integer"); } } else { } else { getErrPrintWriter().println("Error: Unknown option: " + opt); getErrPrintWriter().println("Error: Unknown option: " + opt); return -1; return -1; Loading Loading @@ -3714,10 +3736,13 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" execution of that user if it is currently stopped."); pw.println(" execution of that user if it is currently stopped."); pw.println(" get-current-user"); pw.println(" get-current-user"); pw.println(" Returns id of the current foreground user."); pw.println(" Returns id of the current foreground user."); pw.println(" start-user [-w] <USER_ID>"); pw.println(" start-user [-w] [--display DISPLAY_ID] <USER_ID>"); pw.println(" Start USER_ID in background if it is currently stopped;"); pw.println(" Start USER_ID in background if it is currently stopped;"); pw.println(" use switch-user if you want to start the user in foreground."); pw.println(" use switch-user if you want to start the user in foreground."); pw.println(" -w: wait for start-user to complete and the user to be unlocked."); pw.println(" -w: wait for start-user to complete and the user to be unlocked."); pw.println(" --display <DISPLAY_ID>: allows the user to launch activities in the"); pw.println(" given display, when supported (typically on automotive builds"); pw.println(" wherethe vehicle has multiple displays)"); pw.println(" unlock-user <USER_ID>"); pw.println(" unlock-user <USER_ID>"); pw.println(" Unlock the given user. This will only work if the user doesn't"); pw.println(" Unlock the given user. This will only work if the user doesn't"); pw.println(" have an LSKF (PIN/pattern/password)."); pw.println(" have an LSKF (PIN/pattern/password)."); Loading services/core/java/com/android/server/am/UserController.java +47 −7 Original line number Original line Diff line number Diff line Loading @@ -100,6 +100,7 @@ import android.util.Pair; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import android.view.Display; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; Loading @@ -107,6 +108,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.FactoryResetter; import com.android.server.FactoryResetter; import com.android.server.FgThread; import com.android.server.FgThread; Loading Loading @@ -1071,6 +1073,12 @@ class UserController implements Handler.Callback { Binder.getCallingPid(), UserHandle.USER_ALL); Binder.getCallingPid(), UserHandle.USER_ALL); }); }); } } // TODO(b/239982558): for now we're just updating the user's visibility, but most likely // we'll need to remove this call and handle that as part of the user state workflow // instead. // TODO(b/240613396) also check if multi-display is supported mInjector.getUserManagerInternal().assignUserToDisplay(userId, Display.INVALID_DISPLAY); } } private void finishUserStopping(final int userId, final UserState uss, private void finishUserStopping(final int userId, final UserState uss, Loading Loading @@ -1363,6 +1371,7 @@ class UserController implements Handler.Callback { } } final int profilesToStartSize = profilesToStart.size(); final int profilesToStartSize = profilesToStart.size(); int i = 0; int i = 0; // TODO(b/239982558): pass displayId for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) { for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) { startUser(profilesToStart.get(i).id, /* foreground= */ false); startUser(profilesToStart.get(i).id, /* foreground= */ false); } } Loading @@ -1371,6 +1380,7 @@ class UserController implements Handler.Callback { } } } } // TODO(b/239982558): might need to infer the display id based on parent user /** /** * Starts a user only if it's a profile, with a more relaxed permission requirement: * Starts a user only if it's a profile, with a more relaxed permission requirement: * {@link android.Manifest.permission#MANAGE_USERS} or * {@link android.Manifest.permission#MANAGE_USERS} or Loading Loading @@ -1399,7 +1409,8 @@ class UserController implements Handler.Callback { return false; return false; } } return startUserNoChecks(userId, /* foreground= */ false, /* unlockListener= */ null); return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, /* foreground= */ false, /* unlockListener= */ null); } } @VisibleForTesting @VisibleForTesting Loading Loading @@ -1445,26 +1456,54 @@ class UserController implements Handler.Callback { @Nullable IProgressListener unlockListener) { @Nullable IProgressListener unlockListener) { checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUser"); checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUser"); return startUserNoChecks(userId, foreground, unlockListener); return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, foreground, unlockListener); } // TODO(b/239982558): add javadoc boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId, @Nullable IProgressListener unlockListener) { checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUserOnSecondaryDisplay"); return startUserNoChecks(userId, displayId, /* foreground= */ false, unlockListener); } } private boolean startUserNoChecks(final @UserIdInt int userId, final boolean foreground, private boolean startUserNoChecks(@UserIdInt int userId, int displayId, boolean foreground, @Nullable IProgressListener unlockListener) { @Nullable IProgressListener unlockListener) { TimingsTraceAndSlog t = new TimingsTraceAndSlog(); TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("UserController.startUser-" + userId + "-" + (foreground ? "fg" : "bg")); t.traceBegin("UserController.startUser-" + userId + (displayId == Display.DEFAULT_DISPLAY ? "" : "-display-" + displayId) + "-" + (foreground ? "fg" : "bg")); try { try { return startUserInternal(userId, foreground, unlockListener, t); return startUserInternal(userId, displayId, foreground, unlockListener, t); } finally { } finally { t.traceEnd(); t.traceEnd(); } } } } private boolean startUserInternal(@UserIdInt int userId, boolean foreground, private boolean startUserInternal(@UserIdInt int userId, int displayId, boolean foreground, @Nullable IProgressListener unlockListener, @NonNull TimingsTraceAndSlog t) { @Nullable IProgressListener unlockListener, @NonNull TimingsTraceAndSlog t) { if (DEBUG_MU) { if (DEBUG_MU) { Slogf.i(TAG, "Starting user %d%s", userId, foreground ? " in foreground" : ""); Slogf.i(TAG, "Starting user %d on display %d %s", userId, displayId, foreground ? " in foreground" : ""); } } // TODO(b/240613396) also check if multi-display is supported if (displayId != Display.DEFAULT_DISPLAY) { // TODO(b/239982558): add unit test for the exceptional cases below Preconditions.checkArgument(displayId > 0, "Invalid display id (%d)", displayId); Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot start system user" + " on secondary display (%d)", displayId); Preconditions.checkArgument(!foreground, "Cannot start user %d in foreground AND " + "on secondary display (%d)", userId, displayId); // TODO(b/239982558): for now we're just updating the user's visibility, but most likely // we'll need to remove this call and handle that as part of the user state workflow // instead. // TODO(b/239982558): check if display is valid mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId); } EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId); EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId); final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid(); Loading Loading @@ -1519,6 +1558,7 @@ class UserController implements Handler.Callback { return false; return false; } } // TODO(b/239982558): might need something similar for bg users on secondary display if (foreground && isUserSwitchUiEnabled()) { if (foreground && isUserSwitchUiEnabled()) { t.traceBegin("startFreezingScreen"); t.traceBegin("startFreezingScreen"); mInjector.getWindowManager().startFreezingScreen( mInjector.getWindowManager().startFreezingScreen( Loading services/core/java/com/android/server/pm/UserManagerInternal.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -305,4 +305,7 @@ public abstract class UserManagerInternal { * for users that already existed on-disk from an older version of Android. * for users that already existed on-disk from an older version of Android. */ */ public abstract boolean shouldIgnorePrepareStorageErrors(int userId); public abstract boolean shouldIgnorePrepareStorageErrors(int userId); /** TODO(b/239982558): add javadoc / mention invalid_id is used to unassing */ public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId); } } Loading
core/java/android/app/IActivityManager.aidl +11 −0 Original line number Original line Diff line number Diff line Loading @@ -760,4 +760,15 @@ interface IActivityManager { * </p> * </p> */ */ int getBackgroundRestrictionExemptionReason(int uid); int getBackgroundRestrictionExemptionReason(int uid); // Start (?) of T transactions /** * Similar to {@link #startUserInBackgroundWithListener(int userId, IProgressListener unlockProgressListener), * but setting the user as the visible user of that display (i.e., allowing the user and its * running profiles to launch activities on that display). * * <p>Typically used only by automotive builds when the vehicle has multiple displays. */ boolean startUserInBackgroundOnSecondaryDisplay(int userid, int displayId, IProgressListener unlockProgressListener); } }
services/core/java/com/android/server/am/ActivityManagerService.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -16201,6 +16201,13 @@ public class ActivityManagerService extends IActivityManager.Stub return mUserController.startUser(userId, /* foreground */ true, unlockListener); return mUserController.startUser(userId, /* foreground */ true, unlockListener); } } @Override public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId, @Nullable IProgressListener unlockListener) { // Permission check done inside UserController. return mUserController.startUserOnSecondaryDisplay(userId, displayId, unlockListener); } /** /** * Unlocks the given user. * Unlocks the given user. * *
services/core/java/com/android/server/am/ActivityManagerShellCommand.java +38 −13 Original line number Original line Diff line number Diff line Loading @@ -892,6 +892,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } } } } // TODO(b/239982558): might need to support --displayId as well private int runProfile(PrintWriter pw) throws RemoteException { private int runProfile(PrintWriter pw) throws RemoteException { final PrintWriter err = getErrPrintWriter(); final PrintWriter err = getErrPrintWriter(); String profileFile = null; String profileFile = null; Loading Loading @@ -2034,10 +2035,16 @@ final class ActivityManagerShellCommand extends ShellCommand { int runStartUser(PrintWriter pw) throws RemoteException { int runStartUser(PrintWriter pw) throws RemoteException { boolean wait = false; boolean wait = false; String opt; String opt; int displayId = Display.INVALID_DISPLAY; while ((opt = getNextOption()) != null) { while ((opt = getNextOption()) != null) { if ("-w".equals(opt)) { switch(opt) { case "-w": wait = true; wait = true; } else { break; case "--display": displayId = getDisplayIdFromNextArg(); break; default: getErrPrintWriter().println("Error: unknown option: " + opt); getErrPrintWriter().println("Error: unknown option: " + opt); return -1; return -1; } } Loading @@ -2045,15 +2052,25 @@ final class ActivityManagerShellCommand extends ShellCommand { int userId = Integer.parseInt(getNextArgRequired()); int userId = Integer.parseInt(getNextArgRequired()); final ProgressWaiter waiter = wait ? new ProgressWaiter() : null; final ProgressWaiter waiter = wait ? new ProgressWaiter() : null; boolean success = mInterface.startUserInBackgroundWithListener(userId, waiter); boolean success; String displaySuffix; if (displayId == Display.INVALID_DISPLAY) { success = mInterface.startUserInBackgroundWithListener(userId, waiter); displaySuffix = ""; } else { success = mInterface.startUserInBackgroundOnSecondaryDisplay(userId, displayId, waiter); displaySuffix = " on display " + displayId; } if (wait && success) { if (wait && success) { success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS); success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS); } } if (success) { if (success) { pw.println("Success: user started"); pw.println("Success: user started" + displaySuffix); } else { } else { getErrPrintWriter().println("Error: could not start user"); getErrPrintWriter().println("Error: could not start user" + displaySuffix); } } return 0; return 0; } } Loading Loading @@ -2506,6 +2523,14 @@ final class ActivityManagerShellCommand extends ShellCommand { } } } } private int getDisplayIdFromNextArg() { int displayId = Integer.parseInt(getNextArgRequired()); if (displayId < 0) { throw new IllegalArgumentException("--display must be a non-negative integer"); } return displayId; } int runGetConfig(PrintWriter pw) throws RemoteException { int runGetConfig(PrintWriter pw) throws RemoteException { int days = -1; int days = -1; int displayId = Display.DEFAULT_DISPLAY; int displayId = Display.DEFAULT_DISPLAY; Loading @@ -2524,10 +2549,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } else if (opt.equals("--device")) { } else if (opt.equals("--device")) { inclDevice = true; inclDevice = true; } else if (opt.equals("--display")) { } else if (opt.equals("--display")) { displayId = Integer.parseInt(getNextArgRequired()); displayId = getDisplayIdFromNextArg(); if (displayId < 0) { throw new IllegalArgumentException("--display must be a non-negative integer"); } } else { } else { getErrPrintWriter().println("Error: Unknown option: " + opt); getErrPrintWriter().println("Error: Unknown option: " + opt); return -1; return -1; Loading Loading @@ -3714,10 +3736,13 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" execution of that user if it is currently stopped."); pw.println(" execution of that user if it is currently stopped."); pw.println(" get-current-user"); pw.println(" get-current-user"); pw.println(" Returns id of the current foreground user."); pw.println(" Returns id of the current foreground user."); pw.println(" start-user [-w] <USER_ID>"); pw.println(" start-user [-w] [--display DISPLAY_ID] <USER_ID>"); pw.println(" Start USER_ID in background if it is currently stopped;"); pw.println(" Start USER_ID in background if it is currently stopped;"); pw.println(" use switch-user if you want to start the user in foreground."); pw.println(" use switch-user if you want to start the user in foreground."); pw.println(" -w: wait for start-user to complete and the user to be unlocked."); pw.println(" -w: wait for start-user to complete and the user to be unlocked."); pw.println(" --display <DISPLAY_ID>: allows the user to launch activities in the"); pw.println(" given display, when supported (typically on automotive builds"); pw.println(" wherethe vehicle has multiple displays)"); pw.println(" unlock-user <USER_ID>"); pw.println(" unlock-user <USER_ID>"); pw.println(" Unlock the given user. This will only work if the user doesn't"); pw.println(" Unlock the given user. This will only work if the user doesn't"); pw.println(" have an LSKF (PIN/pattern/password)."); pw.println(" have an LSKF (PIN/pattern/password)."); Loading
services/core/java/com/android/server/am/UserController.java +47 −7 Original line number Original line Diff line number Diff line Loading @@ -100,6 +100,7 @@ import android.util.Pair; import android.util.SparseArray; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import android.view.Display; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; Loading @@ -107,6 +108,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.FactoryResetter; import com.android.server.FactoryResetter; import com.android.server.FgThread; import com.android.server.FgThread; Loading Loading @@ -1071,6 +1073,12 @@ class UserController implements Handler.Callback { Binder.getCallingPid(), UserHandle.USER_ALL); Binder.getCallingPid(), UserHandle.USER_ALL); }); }); } } // TODO(b/239982558): for now we're just updating the user's visibility, but most likely // we'll need to remove this call and handle that as part of the user state workflow // instead. // TODO(b/240613396) also check if multi-display is supported mInjector.getUserManagerInternal().assignUserToDisplay(userId, Display.INVALID_DISPLAY); } } private void finishUserStopping(final int userId, final UserState uss, private void finishUserStopping(final int userId, final UserState uss, Loading Loading @@ -1363,6 +1371,7 @@ class UserController implements Handler.Callback { } } final int profilesToStartSize = profilesToStart.size(); final int profilesToStartSize = profilesToStart.size(); int i = 0; int i = 0; // TODO(b/239982558): pass displayId for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) { for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) { startUser(profilesToStart.get(i).id, /* foreground= */ false); startUser(profilesToStart.get(i).id, /* foreground= */ false); } } Loading @@ -1371,6 +1380,7 @@ class UserController implements Handler.Callback { } } } } // TODO(b/239982558): might need to infer the display id based on parent user /** /** * Starts a user only if it's a profile, with a more relaxed permission requirement: * Starts a user only if it's a profile, with a more relaxed permission requirement: * {@link android.Manifest.permission#MANAGE_USERS} or * {@link android.Manifest.permission#MANAGE_USERS} or Loading Loading @@ -1399,7 +1409,8 @@ class UserController implements Handler.Callback { return false; return false; } } return startUserNoChecks(userId, /* foreground= */ false, /* unlockListener= */ null); return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, /* foreground= */ false, /* unlockListener= */ null); } } @VisibleForTesting @VisibleForTesting Loading Loading @@ -1445,26 +1456,54 @@ class UserController implements Handler.Callback { @Nullable IProgressListener unlockListener) { @Nullable IProgressListener unlockListener) { checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUser"); checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUser"); return startUserNoChecks(userId, foreground, unlockListener); return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, foreground, unlockListener); } // TODO(b/239982558): add javadoc boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId, @Nullable IProgressListener unlockListener) { checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "startUserOnSecondaryDisplay"); return startUserNoChecks(userId, displayId, /* foreground= */ false, unlockListener); } } private boolean startUserNoChecks(final @UserIdInt int userId, final boolean foreground, private boolean startUserNoChecks(@UserIdInt int userId, int displayId, boolean foreground, @Nullable IProgressListener unlockListener) { @Nullable IProgressListener unlockListener) { TimingsTraceAndSlog t = new TimingsTraceAndSlog(); TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("UserController.startUser-" + userId + "-" + (foreground ? "fg" : "bg")); t.traceBegin("UserController.startUser-" + userId + (displayId == Display.DEFAULT_DISPLAY ? "" : "-display-" + displayId) + "-" + (foreground ? "fg" : "bg")); try { try { return startUserInternal(userId, foreground, unlockListener, t); return startUserInternal(userId, displayId, foreground, unlockListener, t); } finally { } finally { t.traceEnd(); t.traceEnd(); } } } } private boolean startUserInternal(@UserIdInt int userId, boolean foreground, private boolean startUserInternal(@UserIdInt int userId, int displayId, boolean foreground, @Nullable IProgressListener unlockListener, @NonNull TimingsTraceAndSlog t) { @Nullable IProgressListener unlockListener, @NonNull TimingsTraceAndSlog t) { if (DEBUG_MU) { if (DEBUG_MU) { Slogf.i(TAG, "Starting user %d%s", userId, foreground ? " in foreground" : ""); Slogf.i(TAG, "Starting user %d on display %d %s", userId, displayId, foreground ? " in foreground" : ""); } } // TODO(b/240613396) also check if multi-display is supported if (displayId != Display.DEFAULT_DISPLAY) { // TODO(b/239982558): add unit test for the exceptional cases below Preconditions.checkArgument(displayId > 0, "Invalid display id (%d)", displayId); Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot start system user" + " on secondary display (%d)", displayId); Preconditions.checkArgument(!foreground, "Cannot start user %d in foreground AND " + "on secondary display (%d)", userId, displayId); // TODO(b/239982558): for now we're just updating the user's visibility, but most likely // we'll need to remove this call and handle that as part of the user state workflow // instead. // TODO(b/239982558): check if display is valid mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId); } EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId); EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId); final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid(); Loading Loading @@ -1519,6 +1558,7 @@ class UserController implements Handler.Callback { return false; return false; } } // TODO(b/239982558): might need something similar for bg users on secondary display if (foreground && isUserSwitchUiEnabled()) { if (foreground && isUserSwitchUiEnabled()) { t.traceBegin("startFreezingScreen"); t.traceBegin("startFreezingScreen"); mInjector.getWindowManager().startFreezingScreen( mInjector.getWindowManager().startFreezingScreen( Loading
services/core/java/com/android/server/pm/UserManagerInternal.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -305,4 +305,7 @@ public abstract class UserManagerInternal { * for users that already existed on-disk from an older version of Android. * for users that already existed on-disk from an older version of Android. */ */ public abstract boolean shouldIgnorePrepareStorageErrors(int userId); public abstract boolean shouldIgnorePrepareStorageErrors(int userId); /** TODO(b/239982558): add javadoc / mention invalid_id is used to unassing */ public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId); } }