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

Commit 27dad1a6 authored by Adam Bookatz's avatar Adam Bookatz Committed by Android (Google) Code Review
Browse files

Merge "Delayed locking is only for mDelayUserDataLocking" into main

parents e9ff7d3a bdf5164a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1427,8 +1427,8 @@ public class UserManager {
    public static final String DISALLOW_RECORD_AUDIO = "no_record_audio";

    /**
     * Specifies if a user is not allowed to run in the background and should be stopped during
     * user switch. The default value is <code>false</code>.
     * Specifies if a user is not allowed to run in the background and should be stopped and locked
     * during user switch. The default value is <code>false</code>.
     *
     * <p>This restriction can be set by device owners and profile owners.
     *
+35 −19
Original line number Diff line number Diff line
@@ -1350,41 +1350,57 @@ class UserController implements Handler.Callback {
    }

    /**
     * For mDelayUserDataLocking mode, storage once unlocked is kept unlocked.
     * Total number of unlocked user storage is limited by mMaxRunningUsers.
     * If there are more unlocked users, evict and lock the least recently stopped user and
     * lock that user's data. Regardless of the mode, ephemeral user is always locked
     * immediately.
     * Returns which user, if any, should be locked when the given user is stopped.
     *
     * For typical (non-mDelayUserDataLocking) devices and users, this will be the provided user.
     *
     * However, for some devices or users (based on {@link #canDelayDataLockingForUser(int)}),
     * storage once unlocked is kept unlocked, even after the user is stopped, so the user to be
     * locked (if any) may differ.
     *
     * For mDelayUserDataLocking devices, the total number of unlocked user storage is limited
     * (currently by mMaxRunningUsers). If there are more unlocked users, evict and lock the least
     * recently stopped user and lock that user's data.
     *
     * Regardless of the mode, ephemeral user is always locked immediately.
     *
     * @return user id to lock. UserHandler.USER_NULL will be returned if no user should be locked.
     */
    @GuardedBy("mLock")
    private int updateUserToLockLU(@UserIdInt int userId, boolean allowDelayedLocking) {
        int userIdToLock = userId;
        // TODO: Decouple the delayed locking flows from mMaxRunningUsers or rename the property to
        // state maximum running unlocked users specifically
        if (canDelayDataLockingForUser(userIdToLock) && allowDelayedLocking
                && !getUserInfo(userId).isEphemeral()
                && !hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND, userId)) {
        if (!canDelayDataLockingForUser(userId)
                || !allowDelayedLocking
                || getUserInfo(userId).isEphemeral()
                || hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND, userId)) {
            return userId;
        }

        // Once we reach here, we are in a delayed locking scenario.
        // Now, no user will be locked, unless the device's policy dictates we should based on the
        // maximum of such users allowed for the device.
        if (mDelayUserDataLocking) {
            // arg should be object, not index
            mLastActiveUsersForDelayedLocking.remove((Integer) userId);
            mLastActiveUsersForDelayedLocking.add(0, userId);
            int totalUnlockedUsers = mStartedUsers.size()
                    + mLastActiveUsersForDelayedLocking.size();
            // TODO: Decouple the delayed locking flows from mMaxRunningUsers. These users aren't
            //  running so this calculation shouldn't be based on this parameter. Also note that
            //  that if these devices ever support background running users (such as profiles), the
            //  implementation is incorrect since starting such users can cause the max to be
            //  exceeded.
            if (totalUnlockedUsers > mMaxRunningUsers) { // should lock a user
                userIdToLock = mLastActiveUsersForDelayedLocking.get(
                final int userIdToLock = mLastActiveUsersForDelayedLocking.get(
                        mLastActiveUsersForDelayedLocking.size() - 1);
                mLastActiveUsersForDelayedLocking
                        .remove(mLastActiveUsersForDelayedLocking.size() - 1);
                Slogf.i(TAG, "finishUserStopped, stopping user:" + userId
                        + " lock user:" + userIdToLock);
            } else {
                Slogf.i(TAG, "finishUserStopped, user:" + userId + ", skip locking");
                // do not lock
                userIdToLock = UserHandle.USER_NULL;
                Slogf.i(TAG, "finishUserStopped: should stop user " + userId
                        + " but should lock user " + userIdToLock);
                return userIdToLock;
            }
        }
        return userIdToLock;
        Slogf.i(TAG, "finishUserStopped: should stop user " + userId + " but without any locking");
        return UserHandle.USER_NULL;
    }

    /**
+28 −23
Original line number Diff line number Diff line
@@ -682,19 +682,19 @@ public class UserControllerTest {
                /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);

        setUpAndStartUserInBackground(TEST_USER_ID);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback= */ null, /* expectLocking= */ true);

        setUpAndStartUserInBackground(TEST_USER_ID1);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);

        setUpAndStartUserInBackground(TEST_USER_ID2);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* delayedLocking= */ false,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* allowDelayedLocking= */ false,
                /* keyEvictedCallback= */ null, /* expectLocking= */ true);

        setUpAndStartUserInBackground(TEST_USER_ID3);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID3, /* delayedLocking= */ false,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID3, /* allowDelayedLocking= */ false,
                /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
    }

@@ -739,21 +739,21 @@ public class UserControllerTest {
        mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
                /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ true);

        // delayedLocking set and no KeyEvictedCallback, so it should not lock.
        // allowDelayedLocking set and no KeyEvictedCallback, so it should not lock.
        setUpAndStartUserInBackground(TEST_USER_ID);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback= */ null, /* expectLocking= */ false);

        setUpAndStartUserInBackground(TEST_USER_ID1);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);

        setUpAndStartUserInBackground(TEST_USER_ID2);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* delayedLocking= */ false,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* allowDelayedLocking= */ false,
                /* keyEvictedCallback= */ null, /* expectLocking= */ true);

        setUpAndStartUserInBackground(TEST_USER_ID3);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID3, /* delayedLocking= */ false,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID3, /* allowDelayedLocking= */ false,
                /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
    }

@@ -843,7 +843,7 @@ public class UserControllerTest {
        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
        setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_PRIVATE);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback */ null, /* expectLocking= */ false);
    }

@@ -855,19 +855,20 @@ public class UserControllerTest {
        mSetFlagsRule.disableFlags(
                android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
        setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_PRIVATE);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback */ null, /* expectLocking= */ true);

        mSetFlagsRule.disableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE);
        mSetFlagsRule.enableFlags(
                android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
        setUpAndStartProfileInBackground(TEST_USER_ID2, UserManager.USER_TYPE_PROFILE_PRIVATE);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback */ null, /* expectLocking= */ true);
    }

    /** Delayed-locking users (as opposed to devices) have no limits on how many can be unlocked. */
    @Test
    public void testStopPrivateProfileWithDelayedLocking_maxRunningUsersBreached()
    public void testStopPrivateProfileWithDelayedLocking_imperviousToNumberOfRunningUsers()
            throws Exception {
        mUserController.setInitialConfig(/* mUserSwitchUiEnabled */ true,
                /* maxRunningUsers= */ 1, /* delayUserDataLocking= */ false);
@@ -875,10 +876,14 @@ public class UserControllerTest {
                android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
        setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_PRIVATE);
        setUpAndStartProfileInBackground(TEST_USER_ID2, UserManager.USER_TYPE_PROFILE_MANAGED);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
                /* keyEvictedCallback */ null, /* expectLocking= */ true);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback */ null, /* expectLocking= */ false);
    }

    /**
        * Tests that when a device/user (managed profile) does not permit delayed locking, then
        * even if allowDelayedLocking is true, the user will still be locked.
    */
    @Test
    public void testStopManagedProfileWithDelayedLocking() throws Exception {
        mUserController.setInitialConfig(/* mUserSwitchUiEnabled */ true,
@@ -886,7 +891,7 @@ public class UserControllerTest {
        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
                android.multiuser.Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE);
        setUpAndStartProfileInBackground(TEST_USER_ID1, UserManager.USER_TYPE_PROFILE_MANAGED);
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
        assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* allowDelayedLocking= */ true,
                /* keyEvictedCallback */ null, /* expectLocking= */ true);
    }

@@ -1087,29 +1092,29 @@ public class UserControllerTest {
        mUserStates.put(userId, mUserController.getStartedUserState(userId));
    }

    private void assertUserLockedOrUnlockedAfterStopping(int userId, boolean delayedLocking,
    private void assertUserLockedOrUnlockedAfterStopping(int userId, boolean allowDelayedLocking,
            KeyEvictedCallback keyEvictedCallback, boolean expectLocking) throws Exception {
        int r = mUserController.stopUser(userId, /* force= */ true, /* delayedLocking= */
                delayedLocking, null, keyEvictedCallback);
        int r = mUserController.stopUser(userId, /* force= */ true, /* allowDelayedLocking= */
                allowDelayedLocking, null, keyEvictedCallback);
        assertThat(r).isEqualTo(ActivityManager.USER_OP_SUCCESS);
        assertUserLockedOrUnlockedState(userId, delayedLocking, expectLocking);
        assertUserLockedOrUnlockedState(userId, allowDelayedLocking, expectLocking);
    }

    private void assertProfileLockedOrUnlockedAfterStopping(int userId, boolean expectLocking)
            throws Exception {
        boolean profileStopped = mUserController.stopProfile(userId);
        assertThat(profileStopped).isTrue();
        assertUserLockedOrUnlockedState(userId, /* delayedLocking= */ false, expectLocking);
        assertUserLockedOrUnlockedState(userId, /* allowDelayedLocking= */ false, expectLocking);
    }

    private void assertUserLockedOrUnlockedState(int userId, boolean delayedLocking,
    private void assertUserLockedOrUnlockedState(int userId, boolean allowDelayedLocking,
            boolean expectLocking) throws InterruptedException, RemoteException {
        // fake all interim steps
        UserState ussUser = mUserStates.get(userId);
        ussUser.setState(UserState.STATE_SHUTDOWN);
        // Passing delayedLocking invalidates incorrect internal data passing but currently there is
        // no easy way to get that information passed through lambda.
        mUserController.finishUserStopped(ussUser, delayedLocking);
        mUserController.finishUserStopped(ussUser, allowDelayedLocking);
        waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS);
        verify(mInjector.mStorageManagerMock, times(expectLocking ? 1 : 0))
                .lockCeStorage(userId);