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

Commit 2b317707 authored by Paul Crowley's avatar Paul Crowley
Browse files

Fix insider attack resistance on headless devices

On HSUM devices where the main user is a permanent admin, we want to
entrust the vendor auth secret only to full users. We generate the
secret when the main user is created, and store it on disk encrypted
using their SP. We also store it in memory so that when each user is
created they can get their own encrypted copy on disk.

Bug: 258560859
Test: atest com.android.server.locksettings
Test: boot without hsum, check that only user 0 writes auth secret
Test: boot with hsum, check that user 0 does not write auth secret
Test: boot with hsum, check user 10 writes auth secret
Test: boot with hsum, create user 11, check that user writes auth secret
Change-Id: I2b3141a573a4457ade0edd0eb989ec7929be006d
parent 738650d9
Loading
Loading
Loading
Loading
+114 −25
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.PROFILE_ENCRY
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.provider.DeviceConfig.NAMESPACE_AUTO_PIN_CONFIRMATION;
import static android.provider.DeviceConfig.NAMESPACE_AUTO_PIN_CONFIRMATION;


import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
@@ -70,6 +71,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase;
import android.hardware.authsecret.IAuthSecret;
import android.hardware.authsecret.IAuthSecret;
@@ -218,6 +220,8 @@ public class LockSettingsService extends ILockSettings.Stub {
    private static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
    private static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_";
    private static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";
    private static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_";


    private static final int HEADLESS_VENDOR_AUTH_SECRET_LENGTH = 32;

    // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
    // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
    // Do not call into ActivityManager while holding mSpManager lock.
    // Do not call into ActivityManager while holding mSpManager lock.
    private final Object mSeparateChallengeLock = new Object();
    private final Object mSeparateChallengeLock = new Object();
@@ -266,6 +270,13 @@ public class LockSettingsService extends ILockSettings.Stub {
    @VisibleForTesting
    @VisibleForTesting
    protected boolean mHasSecureLockScreen;
    protected boolean mHasSecureLockScreen;


    @VisibleForTesting
    protected final Object mHeadlessAuthSecretLock = new Object();

    @VisibleForTesting
    @GuardedBy("mHeadlessAuthSecretLock")
    protected byte[] mAuthSecret;

    protected IGateKeeperService mGateKeeperService;
    protected IGateKeeperService mGateKeeperService;
    protected IAuthSecret mAuthSecretService;
    protected IAuthSecret mAuthSecretService;


@@ -562,6 +573,15 @@ public class LockSettingsService extends ILockSettings.Stub {
                java.security.KeyStore ks) {
                java.security.KeyStore ks) {
            return new ManagedProfilePasswordCache(ks, getUserManager());
            return new ManagedProfilePasswordCache(ks, getUserManager());
        }
        }

        public boolean isHeadlessSystemUserMode() {
            return UserManager.isHeadlessSystemUserMode();
        }

        public boolean isMainUserPermanentAdmin() {
            return Resources.getSystem()
                    .getBoolean(com.android.internal.R.bool.config_isMainUserPermanentAdmin);
        }
    }
    }


    public LockSettingsService(Context context) {
    public LockSettingsService(Context context) {
@@ -1679,7 +1699,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                throw new IllegalStateException("password change failed");
                throw new IllegalStateException("password change failed");
            }
            }


            onSyntheticPasswordKnown(userId, sp);
            onSyntheticPasswordUnlocked(userId, sp);
            setLockCredentialWithSpLocked(credential, sp, userId);
            setLockCredentialWithSpLocked(credential, sp, userId);
            sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
            sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
            return true;
            return true;
@@ -1991,7 +2011,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId);
                Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId);
                return;
                return;
            }
            }
            onSyntheticPasswordKnown(userId, result.syntheticPassword);
            onSyntheticPasswordUnlocked(userId, result.syntheticPassword);
            unlockUserKey(userId, result.syntheticPassword);
            unlockUserKey(userId, result.syntheticPassword);
        }
        }
    }
    }
@@ -2584,43 +2604,112 @@ public class LockSettingsService extends ILockSettings.Stub {
        }
        }
    }
    }


    private void onSyntheticPasswordKnown(@UserIdInt int userId, SyntheticPassword sp) {
    private void onSyntheticPasswordCreated(@UserIdInt int userId, SyntheticPassword sp) {
        onSyntheticPasswordKnown(userId, sp, true);
    }

    private void onSyntheticPasswordUnlocked(@UserIdInt int userId, SyntheticPassword sp) {
        onSyntheticPasswordKnown(userId, sp, false);
    }

    private void onSyntheticPasswordKnown(
            @UserIdInt int userId, SyntheticPassword sp, boolean justCreated) {
        if (mInjector.isGsiRunning()) {
        if (mInjector.isGsiRunning()) {
            Slog.w(TAG, "Running in GSI; skipping calls to AuthSecret and RebootEscrow");
            Slog.w(TAG, "Running in GSI; skipping calls to AuthSecret and RebootEscrow");
            return;
            return;
        }
        }


        mRebootEscrowManager.callToRebootEscrowIfNeeded(userId, sp.getVersion(),
        mRebootEscrowManager.callToRebootEscrowIfNeeded(
                sp.getSyntheticPassword());
                userId, sp.getVersion(), sp.getSyntheticPassword());

        callToAuthSecretIfNeeded(userId, sp, justCreated);
        callToAuthSecretIfNeeded(userId, sp);
    }
    }


    private void callToAuthSecretIfNeeded(@UserIdInt int userId, SyntheticPassword sp) {
    /**
        // If the given user is the primary user, pass the auth secret to the HAL.  Only the system
     * Handles generation, storage, and sending of the vendor auth secret. Here we try to retrieve
        // user can be primary.  Check for the system user ID before calling getUserInfo(), as other
     * the auth secret to send it to the auth secret HAL, generate a fresh secret if need be, store
        // users may still be under construction.
     * it encrypted on disk so that the given user can unlock it in future, and stash it in memory
     * so that when future users are created they can also unlock it.
     *
     * <p>Called whenever the SP of a user is available, except in GSI.
     */
    private void callToAuthSecretIfNeeded(
            @UserIdInt int userId, SyntheticPassword sp, boolean justCreated) {
        if (mAuthSecretService == null) {
        if (mAuthSecretService == null) {
            // If there's no IAuthSecret service, we don't need to maintain a auth secret
            return;
        }
        // User may be partially created, so use the internal user manager interface
        final UserManagerInternal userManagerInternal = mInjector.getUserManagerInternal();
        final UserInfo userInfo = userManagerInternal.getUserInfo(userId);
        if (userInfo == null) {
            // User may be partially deleted, skip this.
            return;
        }
        final byte[] authSecret;
        if (!mInjector.isHeadlessSystemUserMode()) {
            // On non-headless systems, the auth secret is derived from user 0's
            // SP, and only user 0 passes it to the HAL.
            if (userId != USER_SYSTEM) {
                return;
            }
            authSecret = sp.deriveVendorAuthSecret();
        } else if (!mInjector.isMainUserPermanentAdmin() || !userInfo.isFull()) {
            // Only full users can receive or pass on the auth secret.
            // If there is no main permanent admin user, we don't try to create or send
            // an auth secret, since there may sometimes be no full users.
            return;
        } else if (justCreated) {
            if (userInfo.isMain()) {
                // The first user is just being created, so we create a new auth secret
                // at the same time.
                Slog.i(TAG, "Generating new vendor auth secret and storing for user: " + userId);
                authSecret = SecureRandomUtils.randomBytes(HEADLESS_VENDOR_AUTH_SECRET_LENGTH);
                // Store it in memory, for when new users are created.
                synchronized (mHeadlessAuthSecretLock) {
                    mAuthSecret = authSecret;
                }
            } else {
                // A new user is being created. Another user should already have logged in at
                // this point, and therefore the auth secret should be stored in memory.
                synchronized (mHeadlessAuthSecretLock) {
                    authSecret = mAuthSecret;
                }
                if (authSecret == null) {
                    Slog.e(TAG, "Creating non-main user " + userId
                            + " but vendor auth secret is not in memory");
                    return;
                    return;
                }
                }
        if (userId == UserHandle.USER_SYSTEM &&
            }
                mUserManager.getUserInfo(userId).isPrimary()) {
            // Store the auth secret encrypted using the user's SP (which was just created).
            final byte[] secret = sp.deriveVendorAuthSecret();
            mSpManager.writeVendorAuthSecret(authSecret, sp, userId);
        } else {
            // The user already exists, so the auth secret should be stored encrypted
            // with that user's SP.
            authSecret = mSpManager.readVendorAuthSecret(sp, userId);
            if (authSecret == null) {
                Slog.e(TAG, "Unable to read vendor auth secret for user: " + userId);
                return;
            }
            // Store it in memory, for when new users are created.
            synchronized (mHeadlessAuthSecretLock) {
                mAuthSecret = authSecret;
            }
        }
        Slog.i(TAG, "Sending vendor auth secret to IAuthSecret HAL as user: " + userId);
        try {
        try {
                mAuthSecretService.setPrimaryUserCredential(secret);
            mAuthSecretService.setPrimaryUserCredential(authSecret);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
                Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e);
            Slog.w(TAG, "Failed to send vendor auth secret to IAuthSecret HAL", e);
            }
        }
        }
    }
    }


    /**
    /**
     * Creates the synthetic password (SP) for the given user, protects it with an empty LSKF, and
     * Creates the synthetic password (SP) for the given user, protects it with an empty LSKF, and
     * protects the user's CE key with a key derived from the SP.
     * protects the user's CE key with a key derived from the SP.
     * <p>
     *
     * This is called just once in the lifetime of the user: at user creation time (possibly delayed
     * <p>This is called just once in the lifetime of the user: at user creation time (possibly
     * until the time when Weaver is guaranteed to be available), or when upgrading from Android 13
     * delayed until the time when Weaver is guaranteed to be available), or when upgrading from
     * or earlier where users with no LSKF didn't necessarily have an SP.
     * Android 13 or earlier where users with no LSKF didn't necessarily have an SP.
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    SyntheticPassword initializeSyntheticPassword(int userId) {
    SyntheticPassword initializeSyntheticPassword(int userId) {
@@ -2635,7 +2724,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                    LockscreenCredential.createNone(), sp, userId);
                    LockscreenCredential.createNone(), sp, userId);
            setCurrentLskfBasedProtectorId(protectorId, userId);
            setCurrentLskfBasedProtectorId(protectorId, userId);
            setUserKeyProtection(userId, sp.deriveFileBasedEncryptionKey());
            setUserKeyProtection(userId, sp.deriveFileBasedEncryptionKey());
            onSyntheticPasswordKnown(userId, sp);
            onSyntheticPasswordCreated(userId, sp);
            return sp;
            return sp;
        }
        }
    }
    }
@@ -2702,7 +2791,7 @@ public class LockSettingsService extends ILockSettings.Stub {
        }
        }
        mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
        mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);


        onSyntheticPasswordKnown(userId, sp);
        onSyntheticPasswordUnlocked(userId, sp);
    }
    }


    private void setDeviceUnlockedForUser(int userId) {
    private void setDeviceUnlockedForUser(int userId) {
@@ -2990,7 +3079,7 @@ public class LockSettingsService extends ILockSettings.Stub {
                    + "verification.");
                    + "verification.");
            return false;
            return false;
        }
        }
        onSyntheticPasswordKnown(userId, result.syntheticPassword);
        onSyntheticPasswordUnlocked(userId, result.syntheticPassword);
        setLockCredentialWithSpLocked(credential, result.syntheticPassword, userId);
        setLockCredentialWithSpLocked(credential, result.syntheticPassword, userId);
        return true;
        return true;
    }
    }
+32 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChang
import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordMetrics;
import android.content.Context;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
@@ -93,6 +94,9 @@ import java.util.Set;
 *                     while the LSKF is nonempty.
 *                     while the LSKF is nonempty.
 *     SP_E0_NAME, SP_P1_NAME: Information needed to create and use escrow token-based protectors.
 *     SP_E0_NAME, SP_P1_NAME: Information needed to create and use escrow token-based protectors.
 *                             Deleted when escrow token support is disabled for the user.
 *                             Deleted when escrow token support is disabled for the user.
 *     VENDOR_AUTH_SECRET_NAME: A copy of the secret passed using the IAuthSecret interface,
 *                              encrypted using a secret derived from the SP using
 *                              PERSONALIZATION_AUTHSECRET_ENCRYPTION_KEY.
 *
 *
 *     For each protector, stored under the corresponding protector ID:
 *     For each protector, stored under the corresponding protector ID:
 *       SP_BLOB_NAME: The encrypted SP secret (the SP itself or the P0 value).  Always exists.
 *       SP_BLOB_NAME: The encrypted SP secret (the SP itself or the P0 value).  Always exists.
@@ -120,6 +124,7 @@ class SyntheticPasswordManager {
    private static final String PASSWORD_DATA_NAME = "pwd";
    private static final String PASSWORD_DATA_NAME = "pwd";
    private static final String WEAVER_SLOT_NAME = "weaver";
    private static final String WEAVER_SLOT_NAME = "weaver";
    private static final String PASSWORD_METRICS_NAME = "metrics";
    private static final String PASSWORD_METRICS_NAME = "metrics";
    private static final String VENDOR_AUTH_SECRET_NAME = "vendor_auth_secret";


    // used for files associated with the SP itself, not with a particular protector
    // used for files associated with the SP itself, not with a particular protector
    public static final long NULL_PROTECTOR_ID = 0L;
    public static final long NULL_PROTECTOR_ID = 0L;
@@ -158,6 +163,8 @@ class SyntheticPasswordManager {
    private static final byte[] PERSONALIZATION_SP_GK_AUTH = "sp-gk-authentication".getBytes();
    private static final byte[] PERSONALIZATION_SP_GK_AUTH = "sp-gk-authentication".getBytes();
    private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes();
    private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes();
    private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes();
    private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes();
    private static final byte[] PERSONALIZATION_AUTHSECRET_ENCRYPTION_KEY =
            "vendor-authsecret-encryption-key".getBytes();
    private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes();
    private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes();
    private static final byte[] PERSONALIZATION_PASSWORD_HASH = "pw-hash".getBytes();
    private static final byte[] PERSONALIZATION_PASSWORD_HASH = "pw-hash".getBytes();
    private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes();
    private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes();
@@ -249,6 +256,10 @@ class SyntheticPasswordManager {
            return deriveSubkey(PERSONALIZATION_PASSWORD_METRICS);
            return deriveSubkey(PERSONALIZATION_PASSWORD_METRICS);
        }
        }


        public byte[] deriveVendorAuthSecretEncryptionKey() {
            return deriveSubkey(PERSONALIZATION_AUTHSECRET_ENCRYPTION_KEY);
        }

        /**
        /**
         * Assigns escrow data to this synthetic password. This is a prerequisite to call
         * Assigns escrow data to this synthetic password. This is a prerequisite to call
         * {@link SyntheticPassword#recreateFromEscrow}.
         * {@link SyntheticPassword#recreateFromEscrow}.
@@ -1737,4 +1748,25 @@ class SyntheticPasswordManager {
            mListeners.finishBroadcast();
            mListeners.finishBroadcast();
        }
        }
    }
    }

    public void writeVendorAuthSecret(
            @NonNull final byte[] vendorAuthSecret,
            @NonNull final SyntheticPassword sp,
            @UserIdInt final int userId) {
        final byte[] encrypted =
                SyntheticPasswordCrypto.encrypt(
                        sp.deriveVendorAuthSecretEncryptionKey(), new byte[0], vendorAuthSecret);
        saveState(VENDOR_AUTH_SECRET_NAME, encrypted, NULL_PROTECTOR_ID, userId);
        syncState(userId);
    }

    public @Nullable byte[] readVendorAuthSecret(
            @NonNull final SyntheticPassword sp, @UserIdInt final int userId) {
        final byte[] encrypted = loadState(VENDOR_AUTH_SECRET_NAME, NULL_PROTECTOR_ID, userId);
        if (encrypted == null) {
            return null;
        }
        return SyntheticPasswordCrypto.decrypt(
                sp.deriveVendorAuthSecretEncryptionKey(), new byte[0], encrypted);
    }
}
}
+56 −16
Original line number Original line Diff line number Diff line
@@ -49,8 +49,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.security.KeyStore;
import android.security.KeyStore;


import androidx.test.InstrumentationRegistry;
import androidx.test.InstrumentationRegistry;
@@ -83,16 +83,15 @@ public abstract class BaseLockSettingsServiceTests {
    protected static final int MANAGED_PROFILE_USER_ID = 12;
    protected static final int MANAGED_PROFILE_USER_ID = 12;
    protected static final int TURNED_OFF_PROFILE_USER_ID = 17;
    protected static final int TURNED_OFF_PROFILE_USER_ID = 17;
    protected static final int SECONDARY_USER_ID = 20;
    protected static final int SECONDARY_USER_ID = 20;
    protected static final int TERTIARY_USER_ID = 21;


    private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER_ID, null, null,
    protected UserInfo mPrimaryUserInfo;
            UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY
    protected UserInfo mSecondaryUserInfo;
                    | UserInfo.FLAG_MAIN);
    protected UserInfo mTertiaryUserInfo;
    private static final UserInfo SECONDARY_USER_INFO = new UserInfo(SECONDARY_USER_ID, null, null,
            UserInfo.FLAG_INITIALIZED);


    private ArrayList<UserInfo> mPrimaryUserProfiles = new ArrayList<>();
    private ArrayList<UserInfo> mPrimaryUserProfiles = new ArrayList<>();


    LockSettingsService mService;
    LockSettingsServiceTestable mService;
    LockSettingsInternal mLocalService;
    LockSettingsInternal mLocalService;


    MockLockSettingsContext mContext;
    MockLockSettingsContext mContext;
@@ -117,6 +116,7 @@ public abstract class BaseLockSettingsServiceTests {
    FingerprintManager mFingerprintManager;
    FingerprintManager mFingerprintManager;
    FaceManager mFaceManager;
    FaceManager mFaceManager;
    PackageManager mPackageManager;
    PackageManager mPackageManager;
    LockSettingsServiceTestable.MockInjector mInjector;
    @Rule
    @Rule
    public FakeSettingsProviderRule mSettingsRule = FakeSettingsProvider.rule();
    public FakeSettingsProviderRule mSettingsRule = FakeSettingsProvider.rule();


@@ -162,22 +162,61 @@ public abstract class BaseLockSettingsServiceTests {
        mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService,
        mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService,
                mUserManager, mPasswordSlotManager);
                mUserManager, mPasswordSlotManager);
        mAuthSecretService = mock(IAuthSecret.class);
        mAuthSecretService = mock(IAuthSecret.class);
        mService = new LockSettingsServiceTestable(mContext, mStorage,
        mInjector =
                mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
                new LockSettingsServiceTestable.MockInjector(
                mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager,
                        mContext,
                mUserManagerInternal, mDeviceStateCache);
                        mStorage,
                        mKeyStore,
                        mActivityManager,
                        setUpStorageManagerMock(),
                        mSpManager,
                        mGsiService,
                        mRecoverableKeyStoreManager,
                        mUserManagerInternal,
                        mDeviceStateCache);
        mService =
                new LockSettingsServiceTestable(mInjector, mGateKeeperService, mAuthSecretService);
        mService.mHasSecureLockScreen = true;
        mService.mHasSecureLockScreen = true;
        when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
        mPrimaryUserInfo =
        mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
                new UserInfo(
                        PRIMARY_USER_ID,
                        null,
                        null,
                        UserInfo.FLAG_INITIALIZED
                                | UserInfo.FLAG_ADMIN
                                | UserInfo.FLAG_PRIMARY
                                | UserInfo.FLAG_MAIN
                                | UserInfo.FLAG_FULL);
        mSecondaryUserInfo =
                new UserInfo(
                        SECONDARY_USER_ID,
                        null,
                        null,
                        UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_FULL);
        mTertiaryUserInfo =
                new UserInfo(
                        TERTIARY_USER_ID,
                        null,
                        null,
                        UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_FULL);

        when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(mPrimaryUserInfo);
        when(mUserManagerInternal.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(mPrimaryUserInfo);
        mPrimaryUserProfiles.add(mPrimaryUserInfo);
        installChildProfile(MANAGED_PROFILE_USER_ID);
        installChildProfile(MANAGED_PROFILE_USER_ID);
        installAndTurnOffChildProfile(TURNED_OFF_PROFILE_USER_ID);
        installAndTurnOffChildProfile(TURNED_OFF_PROFILE_USER_ID);
        for (UserInfo profile : mPrimaryUserProfiles) {
        for (UserInfo profile : mPrimaryUserProfiles) {
            when(mUserManager.getProfiles(eq(profile.id))).thenReturn(mPrimaryUserProfiles);
            when(mUserManager.getProfiles(eq(profile.id))).thenReturn(mPrimaryUserProfiles);
        }
        }
        when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO);
        when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(mSecondaryUserInfo);
        when(mUserManagerInternal.getUserInfo(eq(SECONDARY_USER_ID)))
                .thenReturn(mSecondaryUserInfo);
        when(mUserManager.getUserInfo(eq(TERTIARY_USER_ID))).thenReturn(mTertiaryUserInfo);
        when(mUserManagerInternal.getUserInfo(eq(TERTIARY_USER_ID))).thenReturn(mTertiaryUserInfo);


        final ArrayList<UserInfo> allUsers = new ArrayList<>(mPrimaryUserProfiles);
        final ArrayList<UserInfo> allUsers = new ArrayList<>(mPrimaryUserProfiles);
        allUsers.add(SECONDARY_USER_INFO);
        allUsers.add(mSecondaryUserInfo);
        allUsers.add(mTertiaryUserInfo);
        when(mUserManager.getUsers()).thenReturn(allUsers);
        when(mUserManager.getUsers()).thenReturn(allUsers);


        when(mActivityManager.unlockUser2(anyInt(), any())).thenAnswer(
        when(mActivityManager.unlockUser2(anyInt(), any())).thenAnswer(
@@ -227,9 +266,10 @@ public abstract class BaseLockSettingsServiceTests {
        userInfo.profileGroupId = PRIMARY_USER_ID;
        userInfo.profileGroupId = PRIMARY_USER_ID;
        mPrimaryUserProfiles.add(userInfo);
        mPrimaryUserProfiles.add(userInfo);
        when(mUserManager.getUserInfo(eq(profileId))).thenReturn(userInfo);
        when(mUserManager.getUserInfo(eq(profileId))).thenReturn(userInfo);
        when(mUserManager.getProfileParent(eq(profileId))).thenReturn(PRIMARY_USER_INFO);
        when(mUserManager.getProfileParent(eq(profileId))).thenReturn(mPrimaryUserInfo);
        when(mUserManager.isUserRunning(eq(profileId))).thenReturn(true);
        when(mUserManager.isUserRunning(eq(profileId))).thenReturn(true);
        when(mUserManager.isUserUnlocked(eq(profileId))).thenReturn(true);
        when(mUserManager.isUserUnlocked(eq(profileId))).thenReturn(true);
        when(mUserManagerInternal.getUserInfo(eq(profileId))).thenReturn(userInfo);
        // TODO(b/258213147): Remove
        // TODO(b/258213147): Remove
        when(mUserManagerInternal.isUserManaged(eq(profileId))).thenReturn(true);
        when(mUserManagerInternal.isUserManaged(eq(profileId))).thenReturn(true);
        when(mDeviceStateCache.isUserOrganizationManaged(eq(profileId)))
        when(mDeviceStateCache.isUserOrganizationManaged(eq(profileId)))
+25 −12
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.RemoteException;
import android.os.storage.IStorageManager;
import android.os.storage.IStorageManager;
import android.security.KeyStore;
import android.security.KeyStore;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.service.gatekeeper.IGateKeeperService;


import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.LockscreenCredential;
import com.android.server.ServiceThread;
import com.android.server.ServiceThread;
@@ -40,7 +41,7 @@ import java.io.FileNotFoundException;


public class LockSettingsServiceTestable extends LockSettingsService {
public class LockSettingsServiceTestable extends LockSettingsService {


    private static class MockInjector extends LockSettingsService.Injector {
    public static class MockInjector extends LockSettingsService.Injector {


        private LockSettingsStorage mLockSettingsStorage;
        private LockSettingsStorage mLockSettingsStorage;
        private KeyStore mKeyStore;
        private KeyStore mKeyStore;
@@ -52,6 +53,9 @@ public class LockSettingsServiceTestable extends LockSettingsService {
        private UserManagerInternal mUserManagerInternal;
        private UserManagerInternal mUserManagerInternal;
        private DeviceStateCache mDeviceStateCache;
        private DeviceStateCache mDeviceStateCache;


        public boolean mIsHeadlessSystemUserMode = false;
        public boolean mIsMainUserPermanentAdmin = false;

        public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
        public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
                IActivityManager activityManager,
                IActivityManager activityManager,
                IStorageManager storageManager, SyntheticPasswordManager spManager,
                IStorageManager storageManager, SyntheticPasswordManager spManager,
@@ -140,19 +144,22 @@ public class LockSettingsServiceTestable extends LockSettingsService {
            return mock(ManagedProfilePasswordCache.class);
            return mock(ManagedProfilePasswordCache.class);
        }
        }


        @Override
        public boolean isHeadlessSystemUserMode() {
            return mIsHeadlessSystemUserMode;
        }
        }


    public MockInjector mInjector;
        @Override
        public boolean isMainUserPermanentAdmin() {
            return mIsMainUserPermanentAdmin;
        }
    }


    protected LockSettingsServiceTestable(Context context,
    protected LockSettingsServiceTestable(
            LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore,
            LockSettingsService.Injector injector,
            IStorageManager storageManager, IActivityManager mActivityManager,
            IGateKeeperService gatekeeper,
            SyntheticPasswordManager spManager, IAuthSecret authSecretService,
            IAuthSecret authSecretService) {
            FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
        super(injector);
            UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
        super(new MockInjector(context, storage, keystore, mActivityManager,
                storageManager, spManager, gsiService, recoverableKeyStoreManager,
                userManagerInternal, deviceStateCache));
        mGateKeeperService = gatekeeper;
        mGateKeeperService = gatekeeper;
        mAuthSecretService = authSecretService;
        mAuthSecretService = authSecretService;
    }
    }
@@ -199,4 +206,10 @@ public class LockSettingsServiceTestable extends LockSettingsService {
        UserInfo userInfo = mUserManager.getUserInfo(userId);
        UserInfo userInfo = mUserManager.getUserInfo(userId);
        return userInfo.isCloneProfile() || userInfo.isManagedProfile();
        return userInfo.isCloneProfile() || userInfo.isManagedProfile();
    }
    }

    void clearAuthSecret() {
        synchronized (mHeadlessAuthSecretLock) {
            mAuthSecret = null;
        }
    }
}
}
+64 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading