diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 060d4c8497dda..8ad8256225d0f 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -400,6 +400,10 @@ class UserController implements Handler.Callback { // Call onBeforeUnlockUser on a worker thread that allows disk I/O FgThread.getHandler().post(() -> { + if (!StorageManager.isUserKeyUnlocked(userId)) { + Slog.w(TAG, "User key got locked unexpectedly, leaving user locked."); + return; + } mInjector.getUserManager().onBeforeUnlockUser(userId); synchronized (mLock) { // Do not proceed if unexpected state @@ -714,14 +718,11 @@ class UserController implements Handler.Callback { void finishUserStopped(UserState uss) { final int userId = uss.mHandle.getIdentifier(); - boolean stopped; + final boolean stopped; ArrayList callbacks; - boolean forceStopUser = false; synchronized (mLock) { callbacks = new ArrayList<>(uss.mStopCallbacks); - if (mStartedUsers.get(userId) != uss) { - stopped = false; - } else if (uss.state != UserState.STATE_SHUTDOWN) { + if (mStartedUsers.get(userId) != uss || uss.state != UserState.STATE_SHUTDOWN) { stopped = false; } else { stopped = true; @@ -729,10 +730,10 @@ class UserController implements Handler.Callback { mStartedUsers.remove(userId); mUserLru.remove(Integer.valueOf(userId)); updateStartedUserArrayLU(); - forceStopUser = true; } } - if (forceStopUser) { + + if (stopped) { mInjector.getUserManagerInternal().removeUserState(userId); mInjector.activityManagerOnUserStopped(userId); // Clean up all state and processes associated with the user. @@ -755,12 +756,23 @@ class UserController implements Handler.Callback { if (getUserInfo(userId).isEphemeral()) { mInjector.getUserManager().removeUserEvenWhenDisallowed(userId); } - // Evict the user's credential encryption key. - try { - getStorageManager().lockUserKey(userId); - } catch (RemoteException re) { - throw re.rethrowAsRuntimeException(); - } + + // Evict the user's credential encryption key. Performed on FgThread to make it + // serialized with call to UserManagerService.onBeforeUnlockUser in finishUserUnlocking + // to prevent data corruption. + FgThread.getHandler().post(() -> { + synchronized (mLock) { + if (mStartedUsers.get(userId) != null) { + Slog.w(TAG, "User was restarted, skipping key eviction"); + return; + } + } + try { + getStorageManager().lockUserKey(userId); + } catch (RemoteException re) { + throw re.rethrowAsRuntimeException(); + } + }); } }