Mandatory Biometrics - Framework (2/N)
Added a separate constant to track if mandatory biometrics requirements are being met
Flag: android.hardware.biometrics.Flags.FLAG_MANDATORY_BIOMETRICS
Test: atest PreAuthInfoTest BiometricServiceTest
Fixes: 339910180
Change-Id: I57518401bfc2b0bd0d9db999affffc4cea484130
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2562c8e..ff38920 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11075,6 +11075,13 @@
public static final String MANDATORY_BIOMETRICS = "mandatory_biometrics";
/**
+ * Whether or not requirements for mandatory biometrics is satisfied.
+ * @hide
+ */
+ public static final String MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED =
+ "mandatory_biometrics_requirements_satisfied";
+
+ /**
* Whether or not active unlock triggers on wake.
* @hide
*/
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 5f23651..2b8b23e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -282,5 +282,6 @@
Settings.Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS,
Settings.Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS,
Settings.Secure.MANDATORY_BIOMETRICS,
+ Settings.Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index c8da8af..cc5302b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -441,5 +441,7 @@
VALIDATORS.put(Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS, NONE_NEGATIVE_LONG_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_MOUSE_KEYS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.MANDATORY_BIOMETRICS, new InclusiveIntegerRangeValidator(0, 1));
+ VALIDATORS.put(Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
+ new InclusiveIntegerRangeValidator(0, 1));
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 8e8a037..8ec835b 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -21,6 +21,7 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_NO_AUTHENTICATION;
+import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE;
@@ -41,6 +42,7 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -54,8 +56,12 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.camera2.CameraManager;
+import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.security.keymint.HardwareAuthenticatorType;
import android.net.Uri;
import android.os.Binder;
@@ -234,6 +240,8 @@
private static final boolean DEFAULT_APP_ENABLED = true;
private static final boolean DEFAULT_ALWAYS_REQUIRE_CONFIRMATION = false;
private static final boolean DEFAULT_MANDATORY_BIOMETRICS_STATUS = false;
+ private static final boolean DEFAULT_MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED_STATUS =
+ true;
// Some devices that shipped before S already have face-specific settings. Instead of
// migrating, which is complicated, let's just keep using the existing settings.
@@ -256,6 +264,8 @@
Settings.Secure.getUriFor(Settings.Secure.BIOMETRIC_APP_ENABLED);
private final Uri MANDATORY_BIOMETRICS_ENABLED =
Settings.Secure.getUriFor(Settings.Secure.MANDATORY_BIOMETRICS);
+ private final Uri MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED = Settings.Secure.getUriFor(
+ Settings.Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED);
private final ContentResolver mContentResolver;
private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks;
@@ -264,6 +274,12 @@
private final Map<Integer, Boolean> mBiometricEnabledForApps = new HashMap<>();
private final Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>();
private final Map<Integer, Boolean> mMandatoryBiometricsEnabled = new HashMap<>();
+ private final Map<Integer, Boolean> mMandatoryBiometricsRequirementsSatisfied =
+ new HashMap<>();
+ private final Map<Integer, Boolean> mFingerprintEnrolledForUser =
+ new HashMap<>();
+ private final Map<Integer, Boolean> mFaceEnrolledForUser =
+ new HashMap<>();
/**
* Creates a content observer.
@@ -288,7 +304,13 @@
mMandatoryBiometricsEnabled.put(context.getUserId(), Settings.Secure.getIntForUser(
mContentResolver, Settings.Secure.MANDATORY_BIOMETRICS,
DEFAULT_MANDATORY_BIOMETRICS_STATUS ? 1 : 0, context.getUserId()) != 0);
+ mMandatoryBiometricsRequirementsSatisfied.put(context.getUserId(),
+ Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
+ DEFAULT_MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED_STATUS ? 1 : 0,
+ context.getUserId()) != 0);
+ addBiometricListenersForMandatoryBiometrics(context);
updateContentObserver();
}
@@ -322,6 +344,10 @@
false /* notifyForDescendants */,
this /* observer */,
UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
}
@Override
@@ -370,6 +396,13 @@
Settings.Secure.MANDATORY_BIOMETRICS,
DEFAULT_MANDATORY_BIOMETRICS_STATUS ? 1 : 0 /* default */,
userId) != 0);
+ } else if (MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED.equals(uri)) {
+ mMandatoryBiometricsRequirementsSatisfied.put(userId, Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED,
+ DEFAULT_MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED_STATUS
+ ? 1 : 0 /* default */,
+ userId) != 0);
}
}
@@ -411,9 +444,15 @@
}
}
- public boolean getMandatoryBiometricsEnabledForUser(int userId) {
+ public boolean getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(int userId) {
return mMandatoryBiometricsEnabled.getOrDefault(userId,
- DEFAULT_MANDATORY_BIOMETRICS_STATUS);
+ DEFAULT_MANDATORY_BIOMETRICS_STATUS)
+ && mMandatoryBiometricsRequirementsSatisfied.getOrDefault(userId,
+ DEFAULT_MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED_STATUS)
+ && mBiometricEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED)
+ && getEnabledForApps(userId)
+ && (mFingerprintEnrolledForUser.getOrDefault(userId, false /* default */)
+ || mFaceEnrolledForUser.getOrDefault(userId, false /* default */));
}
void notifyEnabledOnKeyguardCallbacks(int userId) {
@@ -424,6 +463,79 @@
userId);
}
}
+
+ private void addBiometricListenersForMandatoryBiometrics(Context context) {
+ final FingerprintManager fingerprintManager = context.getSystemService(
+ FingerprintManager.class);
+ final FaceManager faceManager = context.getSystemService(FaceManager.class);
+ if (fingerprintManager != null) {
+ fingerprintManager.addAuthenticatorsRegisteredCallback(
+ new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
+ @Override
+ public void onAllAuthenticatorsRegistered(
+ List<FingerprintSensorPropertiesInternal> list) {
+ if (list == null || list.isEmpty()) {
+ Slog.d(TAG, "No fingerprint authenticators registered.");
+ return;
+ }
+ final FingerprintSensorPropertiesInternal
+ fingerprintSensorProperties = list.get(0);
+ if (fingerprintSensorProperties.sensorStrength
+ == STRENGTH_STRONG) {
+ fingerprintManager.registerBiometricStateListener(
+ new BiometricStateListener() {
+ @Override
+ public void onEnrollmentsChanged(
+ int userId,
+ int sensorId,
+ boolean hasEnrollments
+ ) {
+ if (sensorId == fingerprintSensorProperties
+ .sensorId) {
+ mFingerprintEnrolledForUser.put(userId,
+ hasEnrollments);
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+ if (faceManager != null) {
+ faceManager.addAuthenticatorsRegisteredCallback(
+ new IFaceAuthenticatorsRegisteredCallback.Stub() {
+ @Override
+ public void onAllAuthenticatorsRegistered(
+ List<FaceSensorPropertiesInternal> list) {
+ if (list == null || list.isEmpty()) {
+ Slog.d(TAG, "No face authenticators registered.");
+ return;
+ }
+ final FaceSensorPropertiesInternal
+ faceSensorPropertiesInternal = list.get(0);
+ if (faceSensorPropertiesInternal.sensorStrength
+ == STRENGTH_STRONG) {
+ faceManager.registerBiometricStateListener(
+ new BiometricStateListener() {
+ @Override
+ public void onEnrollmentsChanged(
+ int userId,
+ int sensorId,
+ boolean hasEnrollments
+ ) {
+ if (sensorId
+ == faceSensorPropertiesInternal
+ .sensorId) {
+ mFaceEnrolledForUser.put(userId,
+ hasEnrollments);
+ }
+ }
+ });
+ }
+ }
+ });
+ }
+ }
}
final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient {
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index b9e6563..0bd22f3 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -112,8 +112,8 @@
== BiometricManager.Authenticators.MANDATORY_BIOMETRICS;
if (dropCredentialFallback(promptInfo.getAuthenticators(),
- settingObserver.getMandatoryBiometricsEnabledForUser(userId),
- trustManager)) {
+ settingObserver.getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(
+ userId), trustManager)) {
promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 0f38532..a4222ff 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -1518,7 +1518,8 @@
mBiometricService.onStart();
when(mTrustManager.isInSignificantPlace()).thenReturn(false);
- when(mBiometricService.mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt()))
+ when(mBiometricService.mSettingObserver
+ .getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(anyInt()))
.thenReturn(true);
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
@@ -1540,7 +1541,8 @@
mBiometricService.onStart();
when(mTrustManager.isInSignificantPlace()).thenReturn(false);
- when(mBiometricService.mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt()))
+ when(mBiometricService.mSettingObserver
+ .getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(anyInt()))
.thenReturn(true);
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
@@ -1564,7 +1566,8 @@
mBiometricService.onStart();
when(mTrustManager.isInSignificantPlace()).thenReturn(false);
- when(mBiometricService.mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt()))
+ when(mBiometricService.mSettingObserver
+ .getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(anyInt()))
.thenReturn(true);
setupAuthForOnly(TYPE_CREDENTIAL, Authenticators.DEVICE_CREDENTIAL);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
index b831ef5..240da9f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
@@ -90,7 +90,8 @@
when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt()))
.thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
- when(mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt())).thenReturn(true);
+ when(mSettingObserver.getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(
+ anyInt())).thenReturn(true);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
when(mFaceAuthenticator.getLockoutModeForUser(anyInt()))