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

Commit ab9f17f8 authored by Thomas Cedeno's avatar Thomas Cedeno
Browse files

Move signal locking Keystore

Move the call to have Keystore lock its internals from
UserController to LockSettingsService. Functionally doesn't change
anything, but as LockSettingsService is already responsible for
signaling to unlock Keystore, it makes sense to keep said communication
centralized in the the LockSettingsService system service.

Bug: b/389069078
Flag: com.android.server.flags.keystore_in_memory_cleanup
Test: atest UserControllerTest w/setprop fw.stop_bg_users_on_switch -1
Test: atest StorageManagerServiceTest
Change-Id: I1469a4d2d61528236190ee9dd74aa69d1e37c481
parent 6f6e7d24
Loading
Loading
Loading
Loading
+14 −26
Original line number Diff line number Diff line
@@ -113,9 +113,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.security.KeyStoreAuthorization;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArraySet;
@@ -142,6 +140,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService.UserCompletedEventType;
import com.android.server.SystemServiceManager;
import com.android.server.am.UserState.KeyEvictedCallback;
import com.android.server.locksettings.LockSettingsInternal;
import com.android.server.pm.UserJourneyLogger;
import com.android.server.pm.UserJourneyLogger.UserJourneySession;
import com.android.server.pm.UserManagerInternal;
@@ -1650,7 +1649,6 @@ class UserController implements Handler.Callback {
        }
    }


    private void dispatchUserLocking(@UserIdInt int userId,
            @Nullable List<KeyEvictedCallback> keyEvictedCallbacks) {
        // Evict user secrets that require strong authentication to unlock. This includes locking
@@ -1658,22 +1656,12 @@ class UserController implements Handler.Callback {
        // 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) {
            if (hasStartedUserState(userId)) {
                Slogf.w(TAG, "User was restarted, skipping key eviction");
                return;
            }
            }
            try {
                Slogf.i(TAG, "Locking CE storage for user #" + userId);
                mInjector.getStorageManager().lockCeStorage(userId);
            } catch (RemoteException re) {
                throw re.rethrowAsRuntimeException();
            }
            if (com.android.server.flags.Flags.keystoreInMemoryCleanup()) {
                // Send communication to keystore to wipe key cache for the given userId.
                mInjector.getKeyStoreAuthorization().onUserStorageLocked(userId);
            }
            mInjector.getLockSettingsInternal().lockUser(userId);

            if (keyEvictedCallbacks == null) {
                return;
            }
@@ -4224,6 +4212,7 @@ class UserController implements Handler.Callback {
        private final ActivityManagerService mService;
        private UserManagerService mUserManager;
        private UserManagerInternal mUserManagerInternal;
        private LockSettingsInternal mLockSettingsInternal;
        private PowerManagerInternal mPowerManagerInternal;
        private Handler mHandler;
        private final Object mUserSwitchingDialogLock = new Object();
@@ -4314,6 +4303,13 @@ class UserController implements Handler.Callback {
            return mUserManagerInternal;
        }

        LockSettingsInternal getLockSettingsInternal() {
            if (mLockSettingsInternal == null) {
                mLockSettingsInternal = LocalServices.getService(LockSettingsInternal.class);
            }
            return mLockSettingsInternal;
        }

        PowerManagerInternal getPowerManagerInternal() {
            if (mPowerManagerInternal == null) {
                mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -4333,10 +4329,6 @@ class UserController implements Handler.Callback {
            return mService.mContext.getSystemService(KeyguardManager.class);
        }

        KeyStoreAuthorization getKeyStoreAuthorization() {
            return KeyStoreAuthorization.getInstance();
        }

        void batteryStatsServiceNoteEvent(int code, String name, int uid) {
            mService.mBatteryStatsService.noteEvent(code, name, uid);
        }
@@ -4482,10 +4474,6 @@ class UserController implements Handler.Callback {
            return mService.mAtmInternal.isCallerRecents(callingUid);
        }

        protected IStorageManager getStorageManager() {
            return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
        }

        boolean isHeadlessSystemUserMode() {
            return UserManager.isHeadlessSystemUserMode();
        }
+8 −0
Original line number Diff line number Diff line
@@ -130,6 +130,14 @@ public abstract class LockSettingsInternal {
     */
    public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);


    /**
     * Lock the specified user, i.e. storage, keystore state, and strong auth flags.
     *
     * @param userId the ID of the user being locked.
     */
    public abstract void lockUser(@UserIdInt int userId);

    /**
     * Returns PasswordMetrics object corresponding to the given user's lockscreen password.
     * If the user has a password but its metrics isn't known yet (for example if the device
+35 −26
Original line number Diff line number Diff line
@@ -97,10 +97,8 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.ICeStorageLockEventListener;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.provider.Settings;
import android.security.AndroidKeyStoreMaintenance;
import android.security.KeyStoreAuthorization;
@@ -335,8 +333,6 @@ public class LockSettingsService extends ILockSettings.Stub {
    private final CopyOnWriteArrayList<LockSettingsStateListener> mLockSettingsStateListeners =
            new CopyOnWriteArrayList<>();

    private final StorageManagerInternal mStorageManagerInternal;

    private final Object mGcWorkToken = new Object();

    // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
@@ -589,10 +585,6 @@ public class LockSettingsService extends ILockSettings.Stub {
            return null;
        }

        public StorageManagerInternal getStorageManagerInternal() {
            return LocalServices.getService(StorageManagerInternal.class);
        }

        public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
            return new SyntheticPasswordManager(getContext(), storage, getUserManager(),
                    new PasswordSlotManager());
@@ -723,7 +715,6 @@ public class LockSettingsService extends ILockSettings.Stub {
        mNotificationManager = injector.getNotificationManager();
        mUserManager = injector.getUserManager();
        mStorageManager = injector.getStorageManager();
        mStorageManagerInternal = injector.getStorageManagerInternal();
        mStrongAuthTracker = injector.getStrongAuthTracker();
        mStrongAuthTracker.register(mStrongAuth);
        mGatekeeperPasswords = new LongSparseArray<>();
@@ -969,24 +960,7 @@ public class LockSettingsService extends ILockSettings.Stub {
        mStorage.prefetchUser(UserHandle.USER_SYSTEM);
        mBiometricDeferredQueue.systemReady(mInjector.getFingerprintManager(),
                mInjector.getFaceManager(), mInjector.getBiometricManager());
        mStorageManagerInternal.registerStorageLockEventListener(mCeStorageLockEventListener);
    }

    private final ICeStorageLockEventListener mCeStorageLockEventListener =
            new ICeStorageLockEventListener() {
                @Override
                public void onStorageLocked(int userId) {
                    Slog.i(TAG, "Storage lock event received for " + userId);
                    mHandler.post(() -> {
                        UserProperties userProperties = getUserProperties(userId);
                        if (userProperties != null && userProperties
                                .getAllowStoppingUserWithDelayedLocking()) {
                            int strongAuthRequired = LockPatternUtils.StrongAuthTracker
                                    .getDefaultFlags(mContext);
                            requireStrongAuth(strongAuthRequired, userId);
    }
                    });
                }};

    private void loadEscrowData() {
        mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler);
@@ -1552,6 +1526,10 @@ public class LockSettingsService extends ILockSettings.Stub {
        }
    }

    private void lockKeystore(int userId) {
        mKeyStoreAuthorization.onUserStorageLocked(userId);
    }

    @VisibleForTesting /** Note: this method is overridden in unit tests */
    protected LockscreenCredential getDecryptedPasswordForTiedProfile(int userId)
            throws KeyStoreException, UnrecoverableKeyException,
@@ -3513,6 +3491,32 @@ public class LockSettingsService extends ILockSettings.Stub {
        return true;
    }

    private void lockUser(@UserIdInt int userId) {
        // Lock the user's credential-encrypted storage.
        try {
            Slogf.i(TAG, "Locking CE storage for user #" + userId);
            mInjector.getStorageManager().lockCeStorage(userId);
        } catch (RemoteException re) {
            throw re.rethrowAsRuntimeException();
        }

        // Lock user's Keystore by wiping the user's super key cache.
        if (com.android.server.flags.Flags.keystoreInMemoryCleanup()) {
            lockKeystore(userId);
        }

        // Reset user's strong auth flags
        mHandler.post(() -> {
            UserProperties userProperties = getUserProperties(userId);
            if (userProperties != null && userProperties
                    .getAllowStoppingUserWithDelayedLocking()) {
                int strongAuthRequired = LockPatternUtils.StrongAuthTracker
                        .getDefaultFlags(mContext);
                requireStrongAuth(strongAuthRequired, userId);
            }
        });
    }

    @Override
    public boolean tryUnlockWithCachedUnifiedChallenge(int userId) {
        checkPasswordReadPermission();
@@ -3849,6 +3853,11 @@ public class LockSettingsService extends ILockSettings.Stub {
            return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId);
        }

        @Override
        public void lockUser(@UserIdInt int userId) {
            LockSettingsService.this.lockUser(userId);
        }

        @Override
        public PasswordMetrics getUserPasswordMetrics(int userHandle) {
            final long identity = Binder.clearCallingIdentity();
+9 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -29,8 +30,10 @@ import static org.mockito.Mockito.when;

import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;

import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.pm.UserManagerInternal;
@@ -166,5 +169,11 @@ public final class UserControllerMockedTest {

    private void mockSystemUserHeadlessMode(boolean headless) {
        when(mSpiedUserControllerInjector.isHeadlessSystemUserMode()).thenReturn(headless);
        UserInfo sysInfo = new UserInfo(UserHandle.USER_SYSTEM,
                "User" + UserHandle.USER_SYSTEM, /* iconPath= */ null,
                headless ? UserInfo.FLAG_SYSTEM : UserInfo.FLAG_FULL | UserInfo.FLAG_SYSTEM,
                headless
                    ? UserManager.USER_TYPE_SYSTEM_HEADLESS : UserManager.USER_TYPE_FULL_SYSTEM);
        when(mUserManagerService.getUserInfo(eq(UserHandle.USER_SYSTEM))).thenReturn(sysInfo);
    }
}
+14 −11
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ import com.android.server.AlarmManagerInternal;
import com.android.server.FgThread;
import com.android.server.SystemService;
import com.android.server.am.UserState.KeyEvictedCallback;
import com.android.server.locksettings.LockSettingsInternal;
import com.android.server.pm.UserJourneyLogger;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
@@ -1123,8 +1124,8 @@ public class UserControllerTest {
        // Cannot mock FgThread handler, so confirm that there is no posted message left before
        // checking.
        waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS);
        verify(mInjector.mStorageManagerMock, times(0))
                .lockCeStorage(anyInt());
        verify(mInjector.mLockSettingsInternalMock, times(0))
                .lockUser(anyInt());

        addForegroundUserAndContinueUserSwitch(TEST_USER_ID2, TEST_USER_ID1,
                numberOfUserSwitches, true, false);
@@ -1137,8 +1138,8 @@ public class UserControllerTest {
        ussUser1.setState(UserState.STATE_SHUTDOWN);
        mUserController.finishUserStopped(ussUser1, /* allowDelayedLocking= */ true);
        waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS);
        verify(mInjector.mStorageManagerMock, times(1))
                .lockCeStorage(TEST_USER_ID);
        verify(mInjector.mLockSettingsInternalMock, times(1))
                .lockUser(TEST_USER_ID);
    }

    /** Tests that we stop excess users when starting a background user. */
@@ -2092,8 +2093,8 @@ public class UserControllerTest {
        // no easy way to get that information passed through lambda.
        mUserController.finishUserStopped(ussUser, allowDelayedLocking);
        waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS);
        verify(mInjector.mStorageManagerMock, times(expectLocking ? 1 : 0))
                .lockCeStorage(userId);
        verify(mInjector.mLockSettingsInternalMock, times(expectLocking ? 1 : 0))
                .lockUser(eq(userId));
    }

    private void addForegroundUserAndContinueUserSwitch(int newUserId, int expectedOldUserId,
@@ -2261,6 +2262,7 @@ public class UserControllerTest {

        private final IStorageManager mStorageManagerMock;
        private final UserManagerInternal mUserManagerInternalMock;
        private final LockSettingsInternal mLockSettingsInternalMock;
        private final WindowManagerService mWindowManagerMock;
        private final PowerManagerInternal mPowerManagerInternal;
        private final AlarmManagerInternal mAlarmManagerInternal;
@@ -2283,6 +2285,7 @@ public class UserControllerTest {
            mUiHandler = new TestHandler(mHandlerThread.getLooper());
            mUserManagerMock = mock(UserManagerService.class);
            mUserManagerInternalMock = mock(UserManagerInternal.class);
            mLockSettingsInternalMock = mock(LockSettingsInternal.class);
            mWindowManagerMock = mock(WindowManagerService.class);
            mStorageManagerMock = mock(IStorageManager.class);
            mPowerManagerInternal = mock(PowerManagerInternal.class);
@@ -2314,6 +2317,11 @@ public class UserControllerTest {
            return mUserManagerInternalMock;
        }

        @Override
        LockSettingsInternal getLockSettingsInternal() {
            return mLockSettingsInternalMock;
        }

        @Override
        protected Context getContext() {
            return mCtx;
@@ -2399,11 +2407,6 @@ public class UserControllerTest {
            return true;
        }

        @Override
        protected IStorageManager getStorageManager() {
            return mStorageManagerMock;
        }

        @Override
        void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser,
                String switchingFromSystemUserMessage, String switchingToSystemUserMessage,
Loading