summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java114
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java20
6 files changed, 184 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 378d9ebdaaa8..bad484fa3807 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -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,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 7cece1f5cecc..f9ac02271a27 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -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();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 65d6f45b5c6c..fcd98e0742ea 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -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
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 7354ad4b9ac3..5818133aa2a4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -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";
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 8e0d7be5f44f..2a169b775ca3 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -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() {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
index b33253264317..2b9a05c3ef63 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
@@ -23,6 +23,8 @@ import android.app.trust.TrustManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -34,11 +36,15 @@ public class MockLockSettingsContext extends ContextWrapper {
private StorageManager mStorageManager;
private TrustManager mTrustManager;
private KeyguardManager mKeyguardManager;
+ private FingerprintManager mFingerprintManager;
+ private FaceManager mFaceManager;
+ private PackageManager mPackageManager;
public MockLockSettingsContext(Context base, UserManager userManager,
NotificationManager notificationManager, DevicePolicyManager devicePolicyManager,
StorageManager storageManager, TrustManager trustManager,
- KeyguardManager keyguardManager) {
+ KeyguardManager keyguardManager, FingerprintManager fingerprintManager,
+ FaceManager faceManager, PackageManager packageManager) {
super(base);
mUserManager = userManager;
mNotificationManager = notificationManager;
@@ -46,6 +52,9 @@ public class MockLockSettingsContext extends ContextWrapper {
mStorageManager = storageManager;
mTrustManager = trustManager;
mKeyguardManager = keyguardManager;
+ mFingerprintManager = fingerprintManager;
+ mFaceManager = faceManager;
+ mPackageManager = packageManager;
}
@Override
@@ -62,12 +71,21 @@ public class MockLockSettingsContext extends ContextWrapper {
return mTrustManager;
} else if (KEYGUARD_SERVICE.equals(name)) {
return mKeyguardManager;
+ } else if (FINGERPRINT_SERVICE.equals(name)) {
+ return mFingerprintManager;
+ } else if (FACE_SERVICE.equals(name)) {
+ return mFaceManager;
} else {
throw new RuntimeException("System service not mocked: " + name);
}
}
@Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
public void enforceCallingOrSelfPermission(String permission, String message) {
// Skip permission checks for unit tests.
}