diff options
6 files changed, 77 insertions, 3 deletions
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index 8975191b54c1..9355937b0963 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -170,6 +170,12 @@ public interface BiometricConstants { int BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE = 20; /** + * Biometrics is not allowed to verify in apps. + * @hide + */ + int BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS = 21; + + /** * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused * because the authentication attempt was unsuccessful. * @hide diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index 9bc46b9f382a..a4f7485fcaa5 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -94,6 +94,13 @@ public class BiometricManager { BiometricConstants.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE; /** + * Biometrics is not allowed to verify in apps. + * @hide + */ + public static final int BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS = + BiometricConstants.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS; + + /** * A security vulnerability has been discovered and the sensor is unavailable until a * security update has addressed this issue. This error can be received if for example, * authentication was requested with {@link Authenticators#BIOMETRIC_STRONG}, but the diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java index ac3c02823d0a..b2c616ae5b3c 100644 --- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java +++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java @@ -316,6 +316,7 @@ class PreAuthInfo { Pair<BiometricSensor, Integer> sensorNotEnrolled = null; Pair<BiometricSensor, Integer> sensorLockout = null; Pair<BiometricSensor, Integer> hardwareNotDetected = null; + Pair<BiometricSensor, Integer> biometricAppNotAllowed = null; for (Pair<BiometricSensor, Integer> pair : ineligibleSensors) { final int status = pair.second; if (status == BIOMETRIC_LOCKOUT_TIMED || status == BIOMETRIC_LOCKOUT_PERMANENT) { @@ -327,6 +328,9 @@ class PreAuthInfo { if (status == BIOMETRIC_HARDWARE_NOT_DETECTED) { hardwareNotDetected = pair; } + if (status == BIOMETRIC_NOT_ENABLED_FOR_APPS) { + biometricAppNotAllowed = pair; + } } // If there is a sensor locked out, prioritize lockout over other sensor's error. @@ -339,6 +343,10 @@ class PreAuthInfo { return hardwareNotDetected; } + if (Flags.mandatoryBiometrics() && biometricAppNotAllowed != null) { + return biometricAppNotAllowed; + } + // If the caller requested STRONG, and the device contains both STRONG and non-STRONG // sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's // BIOMETRIC_INSUFFICIENT_STRENGTH error. diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java index 871121472938..407ef1e41aa6 100644 --- a/services/core/java/com/android/server/biometrics/Utils.java +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -321,6 +321,9 @@ public class Utils { case BiometricConstants.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE: biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE; break; + case BiometricConstants.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS: + biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS; + break; default: Slog.e(BiometricService.TAG, "Unhandled result code: " + biometricConstantsCode); biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE; @@ -384,9 +387,12 @@ public class Utils { return BiometricConstants.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED; case MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR: return BiometricConstants.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE; + case BIOMETRIC_NOT_ENABLED_FOR_APPS: + if (Flags.mandatoryBiometrics()) { + return BiometricConstants.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS; + } case BIOMETRIC_DISABLED_BY_DEVICE_POLICY: case BIOMETRIC_HARDWARE_NOT_DETECTED: - case BIOMETRIC_NOT_ENABLED_FOR_APPS: default: return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE; } 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 6b8e414255cd..b4b36125f770 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -558,7 +558,9 @@ public class BiometricServiceTest { waitForIdle(); verify(mReceiver1).onError( eq(BiometricAuthenticator.TYPE_NONE), - eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), + eq(Flags.mandatoryBiometrics() + ? BiometricConstants.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS + : BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(0 /* vendorCode */)); // Enrolled, not disabled in settings, user requires confirmation in settings @@ -1450,7 +1452,9 @@ public class BiometricServiceTest { } @Test - public void testCanAuthenticate_whenBiometricsNotEnabledForApps() throws Exception { + @RequiresFlagsDisabled(Flags.FLAG_MANDATORY_BIOMETRICS) + public void testCanAuthenticate_whenBiometricsNotEnabledForApps_returnsHardwareUnavailable() + throws Exception { setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false); when(mTrustManager.isDeviceSecure(anyInt(), anyInt())) @@ -1468,6 +1472,25 @@ public class BiometricServiceTest { } @Test + @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS) + public void testCanAuthenticate_whenBiometricsNotEnabledForApps() throws Exception { + setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG); + when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false); + when(mTrustManager.isDeviceSecure(anyInt(), anyInt())) + .thenReturn(true); + + // When only biometric is requested + int authenticators = Authenticators.BIOMETRIC_STRONG; + assertEquals(BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS, + invokeCanAuthenticate(mBiometricService, authenticators)); + + // When credential and biometric are requested + authenticators = Authenticators.BIOMETRIC_STRONG | Authenticators.DEVICE_CREDENTIAL; + assertEquals(BiometricManager.BIOMETRIC_SUCCESS, + invokeCanAuthenticate(mBiometricService, authenticators)); + } + + @Test public void testCanAuthenticate_whenNoBiometricSensor() throws Exception { mBiometricService = new BiometricService(mContext, mInjector, mBiometricHandlerProvider); mBiometricService.onStart(); 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 760d38e855a6..b758f57ff407 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java @@ -20,6 +20,7 @@ import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NO import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE; +import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS; import static com.android.server.biometrics.sensors.LockoutTracker.LOCKOUT_NONE; @@ -266,6 +267,29 @@ public class PreAuthInfoTest { @Test @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS) + public void testCalculateByPriority() + throws Exception { + when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false); + when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false); + + BiometricSensor faceSensor = getFaceSensor(); + BiometricSensor fingerprintSensor = getFingerprintSensor(); + PromptInfo promptInfo = new PromptInfo(); + promptInfo.setConfirmationRequested(false /* requireConfirmation */); + promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG); + promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */); + PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, + mSettingObserver, List.of(faceSensor, fingerprintSensor), + 0 /* userId */, promptInfo, TEST_PACKAGE_NAME, + false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager); + + assertThat(preAuthInfo.eligibleSensors).hasSize(0); + assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo( + BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS) public void testMandatoryBiometricsNegativeButtonText_whenSet() throws Exception { when(mTrustManager.isInSignificantPlace()).thenReturn(false); |