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

Commit 9e1f9935 authored by Alex Johnston's avatar Alex Johnston Committed by Android (Google) Code Review
Browse files

Merge "Remove all biometrics data of a user when password is cleared."

parents f60120aa 6183cf99
Loading
Loading
Loading
Loading
+111 −3
Original line number Diff line number Diff line
@@ -61,7 +61,10 @@ import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
import android.hardware.authsecret.V1_0.IAuthSecret;
import android.hardware.biometrics.BiometricManager;
import android.hardware.face.Face;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -117,6 +120,7 @@ import com.android.internal.widget.LockPatternUtils.CredentialType;
import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
@@ -387,8 +391,15 @@ public class LockSettingsService extends ILockSettings.Stub {
            return mContext;
        }

        public Handler getHandler() {
            return new Handler();
        public ServiceThread getServiceThread() {
            ServiceThread handlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
                    true /*allowIo*/);
            handlerThread.start();
            return handlerThread;
        }

        public Handler getHandler(ServiceThread handlerThread) {
            return new Handler(handlerThread.getLooper());
        }

        public LockSettingsStorage getStorage() {
@@ -483,6 +494,23 @@ public class LockSettingsService extends ILockSettings.Stub {
        public boolean isGsiRunning() {
            return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
        }

        public FingerprintManager getFingerprintManager() {
            if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
                return (FingerprintManager) mContext.getSystemService(Context.FINGERPRINT_SERVICE);
            } else {
                return null;
            }
        }

        public FaceManager getFaceManager() {
            if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
                return (FaceManager) mContext.getSystemService(Context.FACE_SERVICE);
            } else {
                return null;
            }
        }

    }

    public LockSettingsService(Context context) {
@@ -495,7 +523,7 @@ public class LockSettingsService extends ILockSettings.Stub {
        mContext = injector.getContext();
        mKeyStore = injector.getKeyStore();
        mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
        mHandler = injector.getHandler();
        mHandler = injector.getHandler(injector.getServiceThread());
        mStrongAuth = injector.getStrongAuth();
        mActivityManager = injector.getActivityManager();

@@ -2713,6 +2741,7 @@ public class LockSettingsService extends ILockSettings.Stub {
            fixateNewestUserKeyAuth(userId);
            unlockKeystore(auth.deriveKeyStorePassword(), userId);
            setKeystorePassword(null, userId);
            removeBiometricsForUser(userId);
        }
        setSyntheticPasswordHandleLocked(newHandle, userId);
        synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
@@ -2728,6 +2757,85 @@ public class LockSettingsService extends ILockSettings.Stub {
        return newHandle;
    }

    private void removeBiometricsForUser(int userId) {
        removeAllFingerprintForUser(userId);
        removeAllFaceForUser(userId);
    }

    private void removeAllFingerprintForUser(final int userId) {
        FingerprintManager mFingerprintManager = mInjector.getFingerprintManager();
        if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
            if (mFingerprintManager.hasEnrolledFingerprints(userId)) {
                mFingerprintManager.setActiveUser(userId);
                CountDownLatch latch = new CountDownLatch(1);
                // For the purposes of M and N, groupId is the same as userId.
                Fingerprint finger = new Fingerprint(null, userId, 0, 0);
                mFingerprintManager.remove(finger, userId,
                        fingerprintManagerRemovalCallback(latch));
                try {
                    latch.await(10000, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    Slog.e(TAG, "Latch interrupted when removing fingerprint", e);
                }
            }
        }
    }

    private void removeAllFaceForUser(final int userId) {
        FaceManager mFaceManager = mInjector.getFaceManager();
        if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
            if (mFaceManager.hasEnrolledTemplates(userId)) {
                mFaceManager.setActiveUser(userId);
                CountDownLatch latch = new CountDownLatch(1);
                Face face = new Face(null, 0, 0);
                mFaceManager.remove(face, userId, faceManagerRemovalCallback(latch));
                try {
                    latch.await(10000, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    Slog.e(TAG, "Latch interrupted when removing face", e);
                }
            }
        }
    }

    private FingerprintManager.RemovalCallback fingerprintManagerRemovalCallback(
            CountDownLatch latch) {
        return new FingerprintManager.RemovalCallback() {
            @Override
            public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence err) {
                Slog.e(TAG, String.format(
                        "Can't remove fingerprint %d in group %d. Reason: %s",
                        fp.getBiometricId(), fp.getGroupId(), err));
                latch.countDown();
            }

            @Override
            public void onRemovalSucceeded(Fingerprint fp, int remaining) {
                if (remaining == 0) {
                    latch.countDown();
                }
            }
        };
    }

    private FaceManager.RemovalCallback faceManagerRemovalCallback(CountDownLatch latch) {
        return new FaceManager.RemovalCallback() {
            @Override
            public void onRemovalError(Face face, int errMsgId, CharSequence err) {
                Slog.e(TAG, String.format("Can't remove face %d. Reason: %s",
                        face.getBiometricId(), err));
                latch.countDown();
            }

            @Override
            public void onRemovalSucceeded(Face face, int remaining) {
                if (remaining == 0) {
                    latch.countDown();
                }
            }
        };
    }

    @GuardedBy("mSpManager")
    private boolean spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
            byte[] savedCredential, int requestedQuality, int userId,
+24 −1
Original line number Diff line number Diff line
@@ -32,8 +32,11 @@ import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DeviceStateCache;
import android.app.trust.TrustManager;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.authsecret.V1_0.IAuthSecret;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.FileUtils;
import android.os.IProgressListener;
import android.os.RemoteException;
@@ -95,6 +98,9 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
    RecoverableKeyStoreManager mRecoverableKeyStoreManager;
    UserManagerInternal mUserManagerInternal;
    DeviceStateCache mDeviceStateCache;
    FingerprintManager mFingerprintManager;
    FaceManager mFaceManager;
    PackageManager mPackageManager;
    protected boolean mHasSecureLockScreen;

    @Override
@@ -114,6 +120,9 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
        mRecoverableKeyStoreManager = mock(RecoverableKeyStoreManager.class);
        mUserManagerInternal = mock(UserManagerInternal.class);
        mDeviceStateCache = mock(DeviceStateCache.class);
        mFingerprintManager = mock(FingerprintManager.class);
        mFaceManager = mock(FaceManager.class);
        mPackageManager = mock(PackageManager.class);

        LocalServices.removeServiceForTest(LockSettingsInternal.class);
        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
@@ -123,7 +132,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {

        mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager,
                mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class),
                mock(KeyguardManager.class));
                mock(KeyguardManager.class), mFingerprintManager, mFaceManager, mPackageManager);
        mStorage = new LockSettingsStorageTestable(mContext,
                new File(getContext().getFilesDir(), "locksettings"));
        File storageDir = mStorage.mStorageDir;
@@ -181,6 +190,8 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
                new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
        when(mUserManagerInternal.isDeviceManaged()).thenReturn(true);
        when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true);
        mockBiometricsHardwareFingerprintsAndTemplates(PRIMARY_USER_ID);
        mockBiometricsHardwareFingerprintsAndTemplates(MANAGED_PROFILE_USER_ID);

        mLocalService = LocalServices.getService(LockSettingsInternal.class);
    }
@@ -233,6 +244,18 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
        return sm;
    }

    private void mockBiometricsHardwareFingerprintsAndTemplates(int userId) {
        // Hardware must be detected and fingerprints must be enrolled
        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
        when(mFingerprintManager.hasEnrolledFingerprints(userId)).thenReturn(true);

        // Hardware must be detected and templates must be enrolled
        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
        when(mFaceManager.isHardwareDetected()).thenReturn(true);
        when(mFaceManager.hasEnrolledTemplates(userId)).thenReturn(true);
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
+3 −3
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.app.admin.DeviceStateCache;
import android.content.Context;
import android.hardware.authsecret.V1_0.IAuthSecret;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserManagerInternal;
@@ -32,6 +31,7 @@ import android.security.KeyStore;
import android.security.keystore.KeyPermanentlyInvalidatedException;

import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;

import java.io.FileNotFoundException;
@@ -70,8 +70,8 @@ public class LockSettingsServiceTestable extends LockSettingsService {
        }

        @Override
        public Handler getHandler() {
            return new Handler(Looper.getMainLooper());
        public Handler getHandler(ServiceThread handlerThread) {
            return new Handler(handlerThread.getLooper());
        }

        @Override
+21 −0
Original line number Diff line number Diff line
@@ -330,6 +330,27 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
                .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, MANAGED_PROFILE_USER_ID);
    }

    public void testSetLockCredential_nullCredential_removeBiometrics() throws RemoteException {
        final String oldCredential = "oldPassword";

        initializeStorageWithCredential(
                PRIMARY_USER_ID,
                oldCredential,
                CREDENTIAL_TYPE_PATTERN,
                PASSWORD_QUALITY_SOMETHING);
        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);

        mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, oldCredential.getBytes(),
                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);

        // Verify fingerprint is removed
        verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any());
        verify(mFaceManager).remove(any(), eq(PRIMARY_USER_ID), any());

        verify(mFingerprintManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any());
        verify(mFaceManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any());
    }

    public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials()
            throws Exception {
        final String parentPassword = "parentPassword";
+6 −1
Original line number Diff line number Diff line
@@ -24,8 +24,11 @@ import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.sqlite.SQLiteDatabase;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.FileUtils;
import android.os.SystemClock;
import android.os.UserManager;
@@ -86,7 +89,9 @@ public class LockSettingsStorageTests extends AndroidTestCase {

        MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
                mock(NotificationManager.class), mock(DevicePolicyManager.class),
                mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class));
                mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class),
                mock(FingerprintManager.class), mock(FaceManager.class),
                mock(PackageManager.class));
        mStorage = new LockSettingsStorageTestable(context,
                new File(getContext().getFilesDir(), "locksettings"));
        mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
Loading