diff --git a/api/current.txt b/api/current.txt index 61089b35e05fc..fa232acaaf321 100644 --- a/api/current.txt +++ b/api/current.txt @@ -17033,6 +17033,7 @@ package android.hardware.biometrics { field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1 field public static final int BIOMETRIC_ERROR_NONE_ENROLLED = 11; // 0xb field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc + field public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; // 0xf field public static final int BIOMETRIC_SUCCESS = 0; // 0x0 } @@ -17067,6 +17068,7 @@ package android.hardware.biometrics { field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb field public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; // 0xe field public static final int BIOMETRIC_ERROR_NO_SPACE = 4; // 0x4 + field public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; // 0xf field public static final int BIOMETRIC_ERROR_TIMEOUT = 3; // 0x3 field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2 field public static final int BIOMETRIC_ERROR_USER_CANCELED = 10; // 0xa diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index 5a1365169eee6..add67aa436c64 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -131,6 +131,14 @@ public interface BiometricConstants { */ int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; + /** + * 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 + * sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}. + */ + int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; + /** * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused * because the authentication attempt was unsuccessful. diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java index bae0fd3ad3b98..6ba7c2a6e7e85 100644 --- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java @@ -17,6 +17,7 @@ package android.hardware.biometrics; import android.app.KeyguardManager; +import android.hardware.biometrics.BiometricManager.Authenticators; import android.hardware.face.FaceManager; /** @@ -141,6 +142,15 @@ public interface BiometricFaceConstants { */ public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; + /** + * 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 + * sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}. + * @hide + */ + int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; + /** * @hide */ diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java index 5c74456eb60a2..0732d760daa9c 100644 --- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java @@ -18,6 +18,7 @@ package android.hardware.biometrics; import android.app.KeyguardManager; import android.compat.annotation.UnsupportedAppUsage; +import android.hardware.biometrics.BiometricManager.Authenticators; import android.hardware.fingerprint.FingerprintManager; /** @@ -127,6 +128,15 @@ public interface BiometricFingerprintConstants { */ public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; + /** + * 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 + * sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}. + * @hide + */ + public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; + /** * @hide */ diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index 125b676e14f77..7d66cae4c8453 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -61,10 +61,20 @@ public class BiometricManager { public static final int BIOMETRIC_ERROR_NO_HARDWARE = BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT; + /** + * 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 + * sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}. + */ + public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = + BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED; + @IntDef({BIOMETRIC_SUCCESS, BIOMETRIC_ERROR_HW_UNAVAILABLE, BIOMETRIC_ERROR_NONE_ENROLLED, - BIOMETRIC_ERROR_NO_HARDWARE}) + BIOMETRIC_ERROR_NO_HARDWARE, + BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED}) @interface BiometricError {} /** diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 07fc9b7a7e5f1..ed1174062cad8 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -25,6 +25,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; import static android.hardware.biometrics.BiometricManager.Authenticators; +import android.annotation.IntDef; import android.app.ActivityManager; import android.app.IActivityManager; import android.app.UserSwitchObserver; @@ -83,6 +84,25 @@ public class BiometricService extends SystemService { static final String TAG = "BiometricService"; private static final boolean DEBUG = true; + private static final int BIOMETRIC_NO_HARDWARE = 0; + private static final int BIOMETRIC_OK = 1; + private static final int BIOMETRIC_DISABLED_BY_DEVICE_POLICY = 2; + private static final int BIOMETRIC_INSUFFICIENT_STRENGTH = 3; + private static final int BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE = 4; + private static final int BIOMETRIC_HARDWARE_NOT_DETECTED = 5; + private static final int BIOMETRIC_NOT_ENROLLED = 6; + private static final int BIOMETRIC_NOT_ENABLED_FOR_APPS = 7; + + @IntDef({BIOMETRIC_NO_HARDWARE, + BIOMETRIC_OK, + BIOMETRIC_DISABLED_BY_DEVICE_POLICY, + BIOMETRIC_INSUFFICIENT_STRENGTH, + BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE, + BIOMETRIC_HARDWARE_NOT_DETECTED, + BIOMETRIC_NOT_ENROLLED, + BIOMETRIC_NOT_ENABLED_FOR_APPS}) + @interface BiometricStatus {} + private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2; private static final int MSG_ON_AUTHENTICATION_REJECTED = 3; private static final int MSG_ON_ERROR = 4; @@ -206,7 +226,7 @@ public class BiometricService extends SystemService { } boolean isAllowDeviceCredential() { - return Utils.isDeviceCredentialAllowed(mBundle); + return Utils.isCredentialRequested(mBundle); } } @@ -372,16 +392,20 @@ public class BiometricService extends SystemService { * strength. * @return a bitfield, see {@link Authenticators} */ - public int getActualStrength() { + int getActualStrength() { return OEMStrength | updatedStrength; } + boolean isDowngraded() { + return OEMStrength != updatedStrength; + } + /** * Stores the updated strength, which takes effect whenever {@link #getActualStrength()} * is checked. * @param newStrength */ - public void updateStrength(int newStrength) { + void updateStrength(int newStrength) { String log = "updateStrength: Before(" + toString() + ")"; updatedStrength = newStrength; log += " After(" + toString() + ")"; @@ -1007,6 +1031,79 @@ public class BiometricService extends SystemService { return isBiometricDisabled; } + private static int biometricStatusToBiometricConstant(@BiometricStatus int status) { + switch (status) { + case BIOMETRIC_NO_HARDWARE: + return BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT; + case BIOMETRIC_OK: + return BiometricConstants.BIOMETRIC_SUCCESS; + case BIOMETRIC_DISABLED_BY_DEVICE_POLICY: + return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE; + case BIOMETRIC_INSUFFICIENT_STRENGTH: + return BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT; + case BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE: + return BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED; + case BIOMETRIC_HARDWARE_NOT_DETECTED: + return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE; + case BIOMETRIC_NOT_ENROLLED: + return BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS; + case BIOMETRIC_NOT_ENABLED_FOR_APPS: + return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE; + default: + return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE; + } + } + + /** + * Returns the status of the authenticator, with errors returned in a specific priority order. + * For example, {@link #BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE} is only returned + * if it has enrollments, and is enabled for apps. + * + * We should only return the modality if the authenticator should be exposed. e.g. + * BIOMETRIC_NOT_ENROLLED_FOR_APPS should not expose the authenticator's type. + * + * @return A Pair with `first` being modality, and `second` being @BiometricStatus + */ + private Pair getStatusForBiometricAuthenticator( + AuthenticatorWrapper authenticator, int userId, String opPackageName, + boolean checkDevicePolicyManager, int requestedStrength) { + if (checkDevicePolicyManager) { + if (isBiometricDisabledByDevicePolicy(authenticator.modality, userId)) { + return new Pair<>(TYPE_NONE, BIOMETRIC_DISABLED_BY_DEVICE_POLICY); + } + } + + final boolean wasStrongEnough = + Utils.isAtLeastStrength(authenticator.OEMStrength, requestedStrength); + final boolean isStrongEnough = + Utils.isAtLeastStrength(authenticator.getActualStrength(), requestedStrength); + + if (wasStrongEnough && !isStrongEnough) { + return new Pair<>(authenticator.modality, + BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE); + } else if (!wasStrongEnough) { + return new Pair<>(TYPE_NONE, BIOMETRIC_INSUFFICIENT_STRENGTH); + } + + try { + if (!authenticator.impl.isHardwareDetected(opPackageName)) { + return new Pair<>(authenticator.modality, BIOMETRIC_HARDWARE_NOT_DETECTED); + } + + if (!authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) { + return new Pair<>(authenticator.modality, BIOMETRIC_NOT_ENROLLED); + } + } catch (RemoteException e) { + return new Pair<>(authenticator.modality, BIOMETRIC_HARDWARE_NOT_DETECTED); + } + + if (!isEnabledForApp(authenticator.modality, userId)) { + return new Pair<>(TYPE_NONE, BIOMETRIC_NOT_ENABLED_FOR_APPS); + } + + return new Pair<>(authenticator.modality, BIOMETRIC_OK); + } + /** * Depending on the requested authentication (credential/biometric combination), checks their * availability. @@ -1029,10 +1126,9 @@ public class BiometricService extends SystemService { private Pair checkAndGetAuthenticators(int userId, Bundle bundle, String opPackageName, boolean checkDevicePolicyManager) throws RemoteException { - final boolean biometricRequested = Utils.isBiometricAllowed(bundle); - final boolean credentialRequested = Utils.isDeviceCredentialAllowed(bundle); + final boolean biometricRequested = Utils.isBiometricRequested(bundle); + final boolean credentialRequested = Utils.isCredentialRequested(bundle); - final boolean biometricOk; final boolean credentialOk = mTrustManager.isDeviceSecure(userId); // Assuming that biometric authenticators are listed in priority-order, the rest of this @@ -1041,96 +1137,56 @@ public class BiometricService extends SystemService { // the correct error. Error strings that are modality-specific should also respect the // priority-order. - // Find first biometric authenticator that's strong enough, detected, enrolled, and enabled. - boolean disabledByDevicePolicy = false; - boolean hasSufficientStrength = false; - boolean isHardwareDetected = false; - boolean hasTemplatesEnrolled = false; - boolean enabledForApps = false; + int firstBiometricModality = TYPE_NONE; + @BiometricStatus int firstBiometricStatus = BIOMETRIC_NO_HARDWARE; + + int biometricModality = TYPE_NONE; + @BiometricStatus int biometricStatus = BIOMETRIC_NO_HARDWARE; - int modality = TYPE_NONE; - int firstHwAvailable = TYPE_NONE; for (AuthenticatorWrapper authenticator : mAuthenticators) { - final int actualStrength = authenticator.getActualStrength(); final int requestedStrength = Utils.getPublicBiometricStrength(bundle); + Pair result = getStatusForBiometricAuthenticator( + authenticator, userId, opPackageName, checkDevicePolicyManager, + requestedStrength); - if (isBiometricDisabledByDevicePolicy(authenticator.modality, userId)) { - disabledByDevicePolicy = true; - continue; - } - disabledByDevicePolicy = false; + biometricStatus = result.second; - if (!Utils.isAtLeastStrength(actualStrength, requestedStrength)) { - continue; - } - hasSufficientStrength = true; + Slog.d(TAG, "Authenticator ID: " + authenticator.id + + " Modality: " + authenticator.modality + + " ReportedModality: " + result.first + + " Status: " + biometricStatus); - if (!authenticator.impl.isHardwareDetected(opPackageName)) { - continue; - } - isHardwareDetected = true; - - if (firstHwAvailable == TYPE_NONE) { - // Store the first one since we want to return the error in correct - // priority order. - firstHwAvailable = authenticator.modality; + if (firstBiometricModality == TYPE_NONE) { + firstBiometricModality = result.first; + firstBiometricStatus = biometricStatus; } - if (!authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) { - continue; + if (biometricStatus == BIOMETRIC_OK) { + biometricModality = result.first; + break; } - hasTemplatesEnrolled = true; - - if (!isEnabledForApp(authenticator.modality, userId)) { - continue; - } - enabledForApps = true; - modality = authenticator.modality; - break; } - biometricOk = !disabledByDevicePolicy - && hasSufficientStrength && isHardwareDetected - && hasTemplatesEnrolled && enabledForApps; - - Slog.d(TAG, "checkAndGetAuthenticators: user=" + userId - + " checkDevicePolicyManager=" + checkDevicePolicyManager - + " isHardwareDetected=" + isHardwareDetected - + " hasTemplatesEnrolled=" + hasTemplatesEnrolled - + " enabledForApps=" + enabledForApps - + " disabledByDevicePolicy=" + disabledByDevicePolicy); - if (biometricRequested && credentialRequested) { - if (credentialOk || biometricOk) { - if (!biometricOk) { + if (credentialOk || biometricStatus == BIOMETRIC_OK) { + if (biometricStatus != BIOMETRIC_OK) { // If there's a problem with biometrics but device credential is // allowed, only show credential UI. bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, Authenticators.DEVICE_CREDENTIAL); } - return new Pair<>(modality, BiometricConstants.BIOMETRIC_SUCCESS); + return new Pair<>(biometricModality, BiometricConstants.BIOMETRIC_SUCCESS); } else { - return new Pair<>(firstHwAvailable, + return new Pair<>(firstBiometricModality, BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS); } } else if (biometricRequested) { - if (biometricOk) { - return new Pair<>(modality, BiometricConstants.BIOMETRIC_SUCCESS); - } else if (disabledByDevicePolicy) { - return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); - } else if (!hasSufficientStrength) { - return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT); - } else if (!isHardwareDetected) { - return new Pair<>(firstHwAvailable, - BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); - } else if (!hasTemplatesEnrolled) { - return new Pair<>(firstHwAvailable, - BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS); - } else if (!enabledForApps) { - return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); + if (biometricStatus == BIOMETRIC_OK) { + return new Pair<>(biometricModality, + biometricStatusToBiometricConstant(biometricStatus)); } else { - Slog.e(TAG, "Unexpected case"); - return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); + return new Pair<>(firstBiometricModality, + biometricStatusToBiometricConstant(firstBiometricStatus)); } } else if (credentialRequested) { if (credentialOk) { diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java index 2d4ab6308a8b2..8f3fd36f411bc 100644 --- a/services/core/java/com/android/server/biometrics/Utils.java +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -80,7 +80,7 @@ public class Utils { * @param authenticators composed of one or more values from {@link Authenticators} * @return true if device credential is allowed. */ - public static boolean isDeviceCredentialAllowed(@Authenticators.Types int authenticators) { + public static boolean isCredentialRequested(@Authenticators.Types int authenticators) { return (authenticators & Authenticators.DEVICE_CREDENTIAL) != 0; } @@ -88,8 +88,8 @@ public class Utils { * @param bundle should be first processed by {@link #combineAuthenticatorBundles(Bundle)} * @return true if device credential is allowed. */ - public static boolean isDeviceCredentialAllowed(Bundle bundle) { - return isDeviceCredentialAllowed(bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED)); + public static boolean isCredentialRequested(Bundle bundle) { + return isCredentialRequested(bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED)); } /** @@ -120,7 +120,7 @@ public class Utils { * @param bundle should be first processed by {@link #combineAuthenticatorBundles(Bundle)} * @return true if biometric authentication is allowed. */ - public static boolean isBiometricAllowed(Bundle bundle) { + public static boolean isBiometricRequested(Bundle bundle) { return getPublicBiometricStrength(bundle) != 0; } @@ -169,7 +169,7 @@ public class Utils { // should be set. final int biometricBits = authenticators & Authenticators.BIOMETRIC_MIN_STRENGTH; if (biometricBits == Authenticators.EMPTY_SET - && isDeviceCredentialAllowed(authenticators)) { + && isCredentialRequested(authenticators)) { return true; } else if (biometricBits == Authenticators.BIOMETRIC_STRONG) { return true; @@ -209,6 +209,9 @@ public class Utils { case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT: biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE; break; + case BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED: + biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED; + break; default: Slog.e(BiometricService.TAG, "Unhandled result code: " + biometricConstantsCode); biometricManagerCode = BiometricManager.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 156cd6e5826d6..e5adb80e6ef9a 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -283,7 +283,7 @@ public class BiometricServiceTest { null /* authenticators */); waitForIdle(); verify(mReceiver1).onError( - eq(BiometricAuthenticator.TYPE_NONE), + eq(BiometricAuthenticator.TYPE_FINGERPRINT), eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(0 /* vendorCode */)); } @@ -1117,14 +1117,14 @@ public class BiometricServiceTest { // STRONG-only auth is not available int authenticators = Authenticators.BIOMETRIC_STRONG; - assertEquals(BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE, + assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED, invokeCanAuthenticate(mBiometricService, authenticators)); invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, authenticators); waitForIdle(); verify(mReceiver1).onError( - eq(BiometricAuthenticator.TYPE_NONE), - eq(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT), + eq(BiometricAuthenticator.TYPE_FINGERPRINT), + eq(BiometricPrompt.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED), eq(0) /* vendorCode */); // Request for weak auth works @@ -1154,7 +1154,7 @@ public class BiometricServiceTest { false /* requireConfirmation */, authenticators); waitForIdle(); - assertTrue(Utils.isDeviceCredentialAllowed(mBiometricService.mCurrentAuthSession.mBundle)); + assertTrue(Utils.isCredentialRequested(mBiometricService.mCurrentAuthSession.mBundle)); verify(mBiometricService.mStatusBarService).showAuthenticationDialog( eq(mBiometricService.mCurrentAuthSession.mBundle), any(IBiometricServiceReceiverInternal.class), @@ -1162,6 +1162,28 @@ public class BiometricServiceTest { anyBoolean() /* requireConfirmation */, anyInt() /* userId */, eq(TEST_PACKAGE_NAME)); + + // Un-downgrading the authenticator allows successful strong auth + for (BiometricService.AuthenticatorWrapper wrapper : mBiometricService.mAuthenticators) { + if (wrapper.id == testId) { + wrapper.updateStrength(Authenticators.BIOMETRIC_STRONG); + } + } + + resetReceiver(); + authenticators = Authenticators.BIOMETRIC_STRONG; + assertEquals(BiometricManager.BIOMETRIC_SUCCESS, + invokeCanAuthenticate(mBiometricService, authenticators)); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, authenticators); + waitForIdle(); + verify(mBiometricService.mStatusBarService).showAuthenticationDialog( + eq(mBiometricService.mCurrentAuthSession.mBundle), + any(IBiometricServiceReceiverInternal.class), + eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */), + anyBoolean() /* requireConfirmation */, + anyInt() /* userId */, + eq(TEST_PACKAGE_NAME)); } @Test(expected = IllegalStateException.class) @@ -1244,6 +1266,19 @@ public class BiometricServiceTest { BiometricService.STATE_AUTH_STARTED); } + @Test + public void testAuthentication_normalAppIgnoresDevicePolicy() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG); + when(mDevicePolicyManager + .getKeyguardDisabledFeatures(any() /* admin */, anyInt() /* userHandle */)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, Authenticators.BIOMETRIC_STRONG); + waitForIdle(); + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_STARTED); + } + @Test public void testWorkAuthentication_faceWorksIfNotDisabledByDevicePolicyManager() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java b/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java index 312ff2ca84a16..df242f3efc169 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java @@ -91,31 +91,31 @@ public class UtilsTest { @Test public void testIsDeviceCredentialAllowed_withIntegerFlags() { int authenticators = 0; - assertFalse(Utils.isDeviceCredentialAllowed(authenticators)); + assertFalse(Utils.isCredentialRequested(authenticators)); authenticators |= Authenticators.DEVICE_CREDENTIAL; - assertTrue(Utils.isDeviceCredentialAllowed(authenticators)); + assertTrue(Utils.isCredentialRequested(authenticators)); authenticators |= Authenticators.BIOMETRIC_WEAK; - assertTrue(Utils.isDeviceCredentialAllowed(authenticators)); + assertTrue(Utils.isCredentialRequested(authenticators)); } @Test public void testIsDeviceCredentialAllowed_withBundle() { Bundle bundle = new Bundle(); - assertFalse(Utils.isDeviceCredentialAllowed(bundle)); + assertFalse(Utils.isCredentialRequested(bundle)); int authenticators = 0; bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators); - assertFalse(Utils.isDeviceCredentialAllowed(bundle)); + assertFalse(Utils.isCredentialRequested(bundle)); authenticators |= Authenticators.DEVICE_CREDENTIAL; bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators); - assertTrue(Utils.isDeviceCredentialAllowed(bundle)); + assertTrue(Utils.isCredentialRequested(bundle)); authenticators |= Authenticators.BIOMETRIC_WEAK; bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators); - assertTrue(Utils.isDeviceCredentialAllowed(bundle)); + assertTrue(Utils.isCredentialRequested(bundle)); } @Test @@ -140,14 +140,14 @@ public class UtilsTest { for (int i = 0; i <= 7; i++) { int authenticators = 1 << i; bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators); - assertTrue(Utils.isBiometricAllowed(bundle)); + assertTrue(Utils.isBiometricRequested(bundle)); } // The rest of the bits are not allowed to integrate with the public APIs for (int i = 8; i < 32; i++) { int authenticators = 1 << i; bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators); - assertFalse(Utils.isBiometricAllowed(bundle)); + assertFalse(Utils.isBiometricRequested(bundle)); } }