Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d43602bb authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "UserController: simplify and fix the delayed user unlocking logic"

parents 0383c7c5 157f3aa5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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,
+32 −46
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
+1 −4
Original line number Diff line number Diff line
@@ -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);