diff options
3 files changed, 34 insertions, 51 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b34fe69f5a3e..ee13118f3e5c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5285,7 +5285,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Tell anyone interested that we are done booting! SystemProperties.set("sys.boot_completed", "1"); SystemProperties.set("dev.bootcomplete", "1"); - mUserController.sendBootCompleted( + mUserController.onBootComplete( new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 226c63862226..216a48ec699c 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -439,11 +439,6 @@ class UserController implements Handler.Callback { mUserLru.add(UserHandle.USER_SYSTEM); mLockPatternUtils = mInjector.getLockPatternUtils(); updateStartedUserArrayLU(); - - // TODO(b/232452368): currently mAllowUserUnlocking is only used on devices with HSUM - // (Headless System User Mode), but on master it will be used by all devices (and hence this - // initial assignment should be removed). - mAllowUserUnlocking = !UserManager.isHeadlessSystemUserMode(); } void setInitialConfig(boolean userSwitchUiEnabled, int maxRunningUsers, @@ -602,8 +597,11 @@ class UserController implements Handler.Callback { if (!mInjector.getUserManager().isPreCreated(userId)) { mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG, userId, 0)); - // In case of headless system user mode, do not send boot complete broadcast for - // system user as it is sent by sendBootCompleted call. + // The "locked boot complete" broadcast for the system user is supposed be sent when + // the device has finished booting. Normally, that is the same time that the system + // user transitions to RUNNING_LOCKED. However, in "headless system user mode", the + // system user is explicitly started before the device has finished booting. In + // that case, we need to wait until onBootComplete() to send the broadcast. if (!(UserManager.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) { // ACTION_LOCKED_BOOT_COMPLETED sendLockedBootCompletedBroadcast(resultTo, userId); @@ -1808,15 +1806,13 @@ class UserController implements Handler.Callback { */ private boolean maybeUnlockUser(@UserIdInt int userId, @Nullable IProgressListener listener) { - // Delay user unlocking for headless system user mode until the system boot - // completes. When the system boot completes, the {@link #onBootCompleted()} - // method unlocks all started users for headless system user mode. This is done - // to prevent unlocking the users too early during the system boot up. - // Otherwise, emulated volumes are mounted too early during the system - // boot up. When vold is reset on boot complete, vold kills all apps/services - // (that use these emulated volumes) before unmounting the volumes(b/241929666). - // In the past, these killings have caused the system to become too unstable on - // some occasions. + // We cannot allow users to be unlocked before PHASE_BOOT_COMPLETED, for two reasons. + // First, emulated volumes aren't supposed to be used until then; StorageManagerService + // assumes it can reset everything upon reaching PHASE_BOOT_COMPLETED. Second, on some + // devices the Weaver HAL needed to unlock the user's storage isn't available until sometime + // shortly before PHASE_BOOT_COMPLETED. The below logic enforces a consistent flow across + // all devices, regardless of their Weaver implementation. + // // Any unlocks that get delayed by this will be done by onBootComplete() instead. if (!mAllowUserUnlocking) { Slogf.i(TAG, "Not unlocking user %d yet because boot hasn't completed", userId); @@ -2424,11 +2420,8 @@ class UserController implements Handler.Callback { } } - /** - * @deprecated TODO(b/232452368): this logic will be merged into sendBootCompleted - */ - @Deprecated - private void onBootCompletedOnHeadlessSystemUserModeDevices() { + void onBootComplete(IIntentReceiver resultTo) { + // Now that PHASE_BOOT_COMPLETED has been reached, user unlocking is allowed. setAllowUserUnlocking(true); // Get a copy of mStartedUsers to use outside of lock. @@ -2436,37 +2429,30 @@ class UserController implements Handler.Callback { synchronized (mLock) { startedUsers = mStartedUsers.clone(); } + // In non-headless system user mode, call finishUserBoot() to transition the system user + // from the BOOTING state to RUNNING_LOCKED, then to RUNNING_UNLOCKED if possible. + // + // In headless system user mode, additional users may have been started, and all users + // (including the system user) that ever get started are started explicitly. In this case, + // we should *not* transition users out of the BOOTING state using finishUserBoot(), as that + // doesn't handle issuing the needed onUserStarting() call, and it would just race with an + // explicit start anyway. We do, however, need to send the "locked boot complete" broadcast + // for the system user, as that got skipped earlier due to the *device* boot not being + // complete yet. We also need to try to unlock all started users, since until now explicit + // user starts didn't proceed to unlocking, due to it being too early in the device boot. + // // USER_SYSTEM must be processed first. It will be first in the array, as its ID is lowest. Preconditions.checkArgument(startedUsers.keyAt(0) == UserHandle.USER_SYSTEM); for (int i = 0; i < startedUsers.size(); i++) { - UserState uss = startedUsers.valueAt(i); - int userId = uss.mHandle.getIdentifier(); - Slogf.i(TAG, "Attempting to unlock user %d on boot complete", userId); - maybeUnlockUser(userId); - } - } - - void sendBootCompleted(IIntentReceiver resultTo) { - if (UserManager.isHeadlessSystemUserMode()) { - // Unlocking users is delayed until boot complete for headless system user mode. - onBootCompletedOnHeadlessSystemUserModeDevices(); - } - - // Get a copy of mStartedUsers to use outside of lock - SparseArray<UserState> startedUsers; - synchronized (mLock) { - startedUsers = mStartedUsers.clone(); - } - for (int i = 0; i < startedUsers.size(); i++) { + int userId = startedUsers.keyAt(i); UserState uss = startedUsers.valueAt(i); if (!UserManager.isHeadlessSystemUserMode()) { finishUserBoot(uss, resultTo); - } else if (uss.mHandle.isSystem()) { - // In case of headless system user mode, send only locked boot complete broadcast - // for system user since finishUserBoot call will be made using other code path; - // for non-system user, do nothing since finishUserBoot will be called elsewhere. - sendLockedBootCompletedBroadcast(resultTo, uss.mHandle.getIdentifier()); - return; + } else { + if (userId == UserHandle.USER_SYSTEM) { + sendLockedBootCompletedBroadcast(resultTo, userId); + } + maybeUnlockUser(userId); } } } diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index 2d2c76c40b10..0b776a3e6642 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -181,11 +181,8 @@ public class UserControllerTest { doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt()); mockIsUsersOnSecondaryDisplaysEnabled(false); // All UserController params are set to default. - mUserController = new UserController(mInjector); - // TODO(b/232452368): need to explicitly call setAllowUserUnlocking(), otherwise most - // tests would fail. But we might need to disable it for the onBootComplete() test (i.e, - // to make sure the users are unlocked at the right time) + mUserController = new UserController(mInjector); mUserController.setAllowUserUnlocking(true); setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS); setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated= */ true, null); |