Loading services/core/java/com/android/server/am/UserController.java +75 −11 Original line number Diff line number Diff line Loading @@ -80,7 +80,6 @@ import android.os.IBinder; import android.os.IProgressListener; import android.os.IRemoteCallback; import android.os.IUserManager; import android.os.Looper; import android.os.Message; import android.os.PowerWhitelistManager; import android.os.Process; Loading Loading @@ -437,6 +436,12 @@ class UserController implements Handler.Callback { /** @see #getLastUserUnlockingUptime */ private volatile long mLastUserUnlockingUptime = 0; /** * Pending user starts waiting for shutdown step to complete. */ @GuardedBy("mLock") private final List<PendingUserStart> mPendingUserStarts = new ArrayList<>(); private final UserLifecycleListener mUserLifecycleListener = new UserLifecycleListener() { @Override public void onUserCreated(UserInfo user, Object token) { Loading Loading @@ -1184,9 +1189,13 @@ class UserController implements Handler.Callback { } else { stopped = true; // User can no longer run. Slogf.i(TAG, "Removing user state from UserController.mStartedUsers for user #" + userId + " as a result of user being stopped"); mStartedUsers.remove(userId); mUserLru.remove(Integer.valueOf(userId)); updateStartedUserArrayLU(); if (allowDelayedLocking && !keyEvictedCallbacks.isEmpty()) { Slogf.wtf(TAG, "Delayed locking enabled while KeyEvictedCallbacks not empty, userId:" Loading @@ -1200,7 +1209,10 @@ class UserController implements Handler.Callback { } } if (stopped) { Slogf.i(TAG, "Removing user state from UserManager.mUserStates for user #" + userId + " as a result of user being stopped"); mInjector.getUserManagerInternal().removeUserState(userId); mInjector.activityManagerOnUserStopped(userId); // Clean up all state and processes associated with the user. // Kill all the processes for the user. Loading Loading @@ -1228,10 +1240,13 @@ class UserController implements Handler.Callback { USER_LIFECYCLE_EVENT_STATE_FINISH); clearSessionId(userId); if (!lockUser) { return; } if (lockUser) { dispatchUserLocking(userIdToLock, keyEvictedCallbacks); } // Resume any existing pending user start, // which was paused while the SHUTDOWN flow of the user was in progress. resumePendingUserStarts(userId); } else { logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER, USER_LIFECYCLE_EVENT_STATE_NONE); Loading @@ -1239,6 +1254,31 @@ class UserController implements Handler.Callback { } } /** * Resume any existing pending user start for the specified userId which was paused * while the shutdown flow of the user was in progress. * Remove all the handled user starts from mPendingUserStarts. * @param userId the id of the user */ private void resumePendingUserStarts(@UserIdInt int userId) { synchronized (mLock) { final List<PendingUserStart> handledUserStarts = new ArrayList<>(); for (PendingUserStart userStart: mPendingUserStarts) { if (userStart.userId == userId) { Slogf.i(TAG, "resumePendingUserStart for" + userStart); mHandler.post(() -> startUser(userStart.userId, userStart.isForeground, userStart.unlockListener)); handledUserStarts.add(userStart); } } // remove all the pending user starts which are now handled mPendingUserStarts.removeAll(handledUserStarts); } } private void dispatchUserLocking(@UserIdInt int userId, @Nullable List<KeyEvictedCallback> keyEvictedCallbacks) { // Evict the user's credential encryption key. Performed on FgThread to make it Loading @@ -1252,6 +1292,7 @@ class UserController implements Handler.Callback { } } try { Slogf.i(TAG, "Locking CE storage for user #" + userId); mInjector.getStorageManager().lockUserKey(userId); } catch (RemoteException re) { throw re.rethrowAsRuntimeException(); Loading Loading @@ -1657,10 +1698,11 @@ class UserController implements Handler.Callback { updateStartedUserArrayLU(); needStart = true; updateUmState = true; } else if (uss.state == UserState.STATE_SHUTDOWN && !isCallingOnHandlerThread()) { } else if (uss.state == UserState.STATE_SHUTDOWN) { Slogf.i(TAG, "User #" + userId + " is shutting down - will start after full stop"); mHandler.post(() -> startUser(userId, foreground, unlockListener)); + " is shutting down - will start after full shutdown"); mPendingUserStarts.add(new PendingUserStart(userId, foreground, unlockListener)); t.traceEnd(); // updateStartedUserArrayStarting return true; } Loading Loading @@ -1818,10 +1860,6 @@ class UserController implements Handler.Callback { return true; } private boolean isCallingOnHandlerThread() { return Looper.myLooper() == mHandler.getLooper(); } /** * Start user, if its not already running, and bring it to foreground. */ Loading Loading @@ -3390,6 +3428,32 @@ class UserController implements Handler.Callback { } } /** * Helper class for keeping track of user starts which are paused while user's * shutdown is taking place. */ private static class PendingUserStart { public final @UserIdInt int userId; public final boolean isForeground; public final IProgressListener unlockListener; PendingUserStart(int userId, boolean foreground, IProgressListener unlockListener) { this.userId = userId; this.isForeground = foreground; this.unlockListener = unlockListener; } @Override public String toString() { return "PendingUserStart{" + "userId=" + userId + ", isForeground=" + isForeground + ", unlockListener=" + unlockListener + '}'; } } @VisibleForTesting static class Injector { private final ActivityManagerService mService; Loading Loading
services/core/java/com/android/server/am/UserController.java +75 −11 Original line number Diff line number Diff line Loading @@ -80,7 +80,6 @@ import android.os.IBinder; import android.os.IProgressListener; import android.os.IRemoteCallback; import android.os.IUserManager; import android.os.Looper; import android.os.Message; import android.os.PowerWhitelistManager; import android.os.Process; Loading Loading @@ -437,6 +436,12 @@ class UserController implements Handler.Callback { /** @see #getLastUserUnlockingUptime */ private volatile long mLastUserUnlockingUptime = 0; /** * Pending user starts waiting for shutdown step to complete. */ @GuardedBy("mLock") private final List<PendingUserStart> mPendingUserStarts = new ArrayList<>(); private final UserLifecycleListener mUserLifecycleListener = new UserLifecycleListener() { @Override public void onUserCreated(UserInfo user, Object token) { Loading Loading @@ -1184,9 +1189,13 @@ class UserController implements Handler.Callback { } else { stopped = true; // User can no longer run. Slogf.i(TAG, "Removing user state from UserController.mStartedUsers for user #" + userId + " as a result of user being stopped"); mStartedUsers.remove(userId); mUserLru.remove(Integer.valueOf(userId)); updateStartedUserArrayLU(); if (allowDelayedLocking && !keyEvictedCallbacks.isEmpty()) { Slogf.wtf(TAG, "Delayed locking enabled while KeyEvictedCallbacks not empty, userId:" Loading @@ -1200,7 +1209,10 @@ class UserController implements Handler.Callback { } } if (stopped) { Slogf.i(TAG, "Removing user state from UserManager.mUserStates for user #" + userId + " as a result of user being stopped"); mInjector.getUserManagerInternal().removeUserState(userId); mInjector.activityManagerOnUserStopped(userId); // Clean up all state and processes associated with the user. // Kill all the processes for the user. Loading Loading @@ -1228,10 +1240,13 @@ class UserController implements Handler.Callback { USER_LIFECYCLE_EVENT_STATE_FINISH); clearSessionId(userId); if (!lockUser) { return; } if (lockUser) { dispatchUserLocking(userIdToLock, keyEvictedCallbacks); } // Resume any existing pending user start, // which was paused while the SHUTDOWN flow of the user was in progress. resumePendingUserStarts(userId); } else { logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER, USER_LIFECYCLE_EVENT_STATE_NONE); Loading @@ -1239,6 +1254,31 @@ class UserController implements Handler.Callback { } } /** * Resume any existing pending user start for the specified userId which was paused * while the shutdown flow of the user was in progress. * Remove all the handled user starts from mPendingUserStarts. * @param userId the id of the user */ private void resumePendingUserStarts(@UserIdInt int userId) { synchronized (mLock) { final List<PendingUserStart> handledUserStarts = new ArrayList<>(); for (PendingUserStart userStart: mPendingUserStarts) { if (userStart.userId == userId) { Slogf.i(TAG, "resumePendingUserStart for" + userStart); mHandler.post(() -> startUser(userStart.userId, userStart.isForeground, userStart.unlockListener)); handledUserStarts.add(userStart); } } // remove all the pending user starts which are now handled mPendingUserStarts.removeAll(handledUserStarts); } } private void dispatchUserLocking(@UserIdInt int userId, @Nullable List<KeyEvictedCallback> keyEvictedCallbacks) { // Evict the user's credential encryption key. Performed on FgThread to make it Loading @@ -1252,6 +1292,7 @@ class UserController implements Handler.Callback { } } try { Slogf.i(TAG, "Locking CE storage for user #" + userId); mInjector.getStorageManager().lockUserKey(userId); } catch (RemoteException re) { throw re.rethrowAsRuntimeException(); Loading Loading @@ -1657,10 +1698,11 @@ class UserController implements Handler.Callback { updateStartedUserArrayLU(); needStart = true; updateUmState = true; } else if (uss.state == UserState.STATE_SHUTDOWN && !isCallingOnHandlerThread()) { } else if (uss.state == UserState.STATE_SHUTDOWN) { Slogf.i(TAG, "User #" + userId + " is shutting down - will start after full stop"); mHandler.post(() -> startUser(userId, foreground, unlockListener)); + " is shutting down - will start after full shutdown"); mPendingUserStarts.add(new PendingUserStart(userId, foreground, unlockListener)); t.traceEnd(); // updateStartedUserArrayStarting return true; } Loading Loading @@ -1818,10 +1860,6 @@ class UserController implements Handler.Callback { return true; } private boolean isCallingOnHandlerThread() { return Looper.myLooper() == mHandler.getLooper(); } /** * Start user, if its not already running, and bring it to foreground. */ Loading Loading @@ -3390,6 +3428,32 @@ class UserController implements Handler.Callback { } } /** * Helper class for keeping track of user starts which are paused while user's * shutdown is taking place. */ private static class PendingUserStart { public final @UserIdInt int userId; public final boolean isForeground; public final IProgressListener unlockListener; PendingUserStart(int userId, boolean foreground, IProgressListener unlockListener) { this.userId = userId; this.isForeground = foreground; this.unlockListener = unlockListener; } @Override public String toString() { return "PendingUserStart{" + "userId=" + userId + ", isForeground=" + isForeground + ", unlockListener=" + unlockListener + '}'; } } @VisibleForTesting static class Injector { private final ActivityManagerService mService; Loading