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

Commit 475a75bd authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add lockout and mandatory biometric error constant" into main

parents 9024d69f bb06e31e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -162,6 +162,13 @@ public interface BiometricConstants {
     * @hide
     */
    int BIOMETRIC_ERROR_POWER_PRESSED = 19;

    /**
     * Mandatory biometrics is not in effect.
     * @hide
     */
    int BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE = 20;

    /**
     * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused
     * because the authentication attempt was unsuccessful.
+17 −1
Original line number Diff line number Diff line
@@ -79,6 +79,20 @@ public class BiometricManager {
    public static final int BIOMETRIC_ERROR_NO_HARDWARE =
            BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;

    /**
     * Lockout error.
     * @hide
     */
    public static final int BIOMETRIC_ERROR_LOCKOUT =
            BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;

    /**
     * Mandatory biometrics is not effective.
     * @hide
     */
    public static final int BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE =
            BiometricConstants.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE;

    /**
     * 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,
@@ -113,7 +127,9 @@ public class BiometricManager {
            BIOMETRIC_ERROR_HW_UNAVAILABLE,
            BIOMETRIC_ERROR_NONE_ENROLLED,
            BIOMETRIC_ERROR_NO_HARDWARE,
            BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED})
            BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
            BIOMETRIC_ERROR_LOCKOUT,
            BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface BiometricError {}

+11 −21
Original line number Diff line number Diff line
@@ -77,13 +77,15 @@ class PreAuthInfo {
    private final int mBiometricStrengthRequested;
    private final BiometricCameraManager mBiometricCameraManager;
    private final boolean mOnlyMandatoryBiometricsRequested;
    private final boolean mIsMandatoryBiometricsAuthentication;

    private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
            boolean credentialRequested, List<BiometricSensor> eligibleSensors,
            List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
            PromptInfo promptInfo, int userId, Context context,
            BiometricCameraManager biometricCameraManager,
            boolean isOnlyMandatoryBiometricsRequested) {
            boolean isOnlyMandatoryBiometricsRequested,
            boolean isMandatoryBiometricsAuthentication) {
        mBiometricRequested = biometricRequested;
        mBiometricStrengthRequested = biometricStrengthRequested;
        mBiometricCameraManager = biometricCameraManager;
@@ -97,6 +99,7 @@ class PreAuthInfo {
        this.userId = userId;
        this.context = context;
        this.mOnlyMandatoryBiometricsRequested = isOnlyMandatoryBiometricsRequested;
        this.mIsMandatoryBiometricsAuthentication = isMandatoryBiometricsAuthentication;
    }

    static PreAuthInfo create(ITrustManager trustManager,
@@ -110,10 +113,12 @@ class PreAuthInfo {

        final boolean isOnlyMandatoryBiometricsRequested = promptInfo.getAuthenticators()
                == BiometricManager.Authenticators.MANDATORY_BIOMETRICS;
        boolean isMandatoryBiometricsAuthentication = false;

        if (dropCredentialFallback(promptInfo.getAuthenticators(),
                settingObserver.getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(
                        userId), trustManager)) {
            isMandatoryBiometricsAuthentication = true;
            promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
            promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
        }
@@ -166,7 +171,8 @@ class PreAuthInfo {

        return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested,
                eligibleSensors, ineligibleSensors, credentialAvailable, promptInfo, userId,
                context, biometricCameraManager, isOnlyMandatoryBiometricsRequested);
                context, biometricCameraManager, isOnlyMandatoryBiometricsRequested,
                isMandatoryBiometricsAuthentication);
    }

    private static boolean dropCredentialFallback(int authenticators,
@@ -387,25 +393,6 @@ class PreAuthInfo {
                    status = CREDENTIAL_NOT_ENROLLED;
                }
            }
        } else if (Flags.mandatoryBiometrics() && mOnlyMandatoryBiometricsRequested) {
            if (!eligibleSensors.isEmpty()) {
                for (BiometricSensor sensor : eligibleSensors) {
                    modality |= sensor.modality;
                }

                if (modality == TYPE_FACE && cameraPrivacyEnabled) {
                    // If the only modality requested is face, credential is unavailable,
                    // and the face sensor privacy is enabled then return
                    // BIOMETRIC_SENSOR_PRIVACY_ENABLED.
                    //
                    // Note: This sensor will not be eligible for calls to authenticate.
                    status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
                } else {
                    status = AUTHENTICATOR_OK;
                }
            } else {
                status = MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR;
            }
        } else if (mBiometricRequested) {
            if (!eligibleSensors.isEmpty()) {
                for (BiometricSensor sensor : eligibleSensors) {
@@ -434,6 +421,9 @@ class PreAuthInfo {
        } else if (credentialRequested) {
            modality |= TYPE_CREDENTIAL;
            status = credentialAvailable ? AUTHENTICATOR_OK : CREDENTIAL_NOT_ENROLLED;
        } else if (Flags.mandatoryBiometrics() && mOnlyMandatoryBiometricsRequested
                && !mIsMandatoryBiometricsAuthentication) {
            status = MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR;
        } else {
            // This should not be possible via the public API surface and is here mainly for
            // "correctness". An exception should have been thrown before getting here.
+10 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NOT_ENROLLED;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NO_HARDWARE;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_SENSOR_PRIVACY_ENABLED;
import static com.android.server.biometrics.PreAuthInfo.CREDENTIAL_NOT_ENROLLED;
import static com.android.server.biometrics.PreAuthInfo.MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,6 +49,7 @@ import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricPrompt.AuthenticationResultType;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorProperties;
@@ -309,11 +311,16 @@ public class Utils {
                break;
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
                biometricManagerCode = BiometricManager.BIOMETRIC_SUCCESS;
                biometricManagerCode = Flags.mandatoryBiometrics()
                        ? BiometricManager.BIOMETRIC_ERROR_LOCKOUT
                        : BiometricManager.BIOMETRIC_SUCCESS;
                break;
            case BiometricConstants.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED:
                biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
                break;
            case BiometricConstants.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE:
                biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE;
                break;
            default:
                Slog.e(BiometricService.TAG, "Unhandled result code: " + biometricConstantsCode);
                biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
@@ -375,6 +382,8 @@ public class Utils {
                return BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
            case BIOMETRIC_SENSOR_PRIVACY_ENABLED:
                return BiometricConstants.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED;
            case MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR:
                return BiometricConstants.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE;
            case BIOMETRIC_DISABLED_BY_DEVICE_POLICY:
            case BIOMETRIC_HARDWARE_NOT_DETECTED:
            case BIOMETRIC_NOT_ENABLED_FOR_APPS:
+33 −2
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -1488,15 +1489,30 @@ public class BiometricServiceTest {
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_MANDATORY_BIOMETRICS)
    public void testCanAuthenticate_whenLockoutTimed() throws Exception {
        testCanAuthenticate_whenLockedOut(LockoutTracker.LOCKOUT_TIMED);
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_MANDATORY_BIOMETRICS)
    public void testCanAuthenticate_whenLockoutPermanent() throws Exception {
        testCanAuthenticate_whenLockedOut(LockoutTracker.LOCKOUT_PERMANENT);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
    public void testCanAuthenticate_whenLockoutTimed_returnsLockoutError() throws Exception {
        testCanAuthenticate_whenLockedOut_returnLockoutError(LockoutTracker.LOCKOUT_TIMED);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
    public void testCanAuthenticate_whenLockoutPermanent_returnsLockoutError() throws Exception {
        testCanAuthenticate_whenLockedOut_returnLockoutError(LockoutTracker.LOCKOUT_PERMANENT);
    }

    @RequiresFlagsDisabled(Flags.FLAG_MANDATORY_BIOMETRICS)
    private void testCanAuthenticate_whenLockedOut(@LockoutTracker.LockoutMode int lockoutMode)
            throws Exception {
        // When only biometric is requested, and sensor is strong enough
@@ -1510,6 +1526,21 @@ public class BiometricServiceTest {
                invokeCanAuthenticate(mBiometricService, Authenticators.BIOMETRIC_STRONG));
    }

    @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
    private void testCanAuthenticate_whenLockedOut_returnLockoutError(
            @LockoutTracker.LockoutMode int lockoutMode)
            throws Exception {
        // When only biometric is requested, and sensor is strong enough
        setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);

        when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
                .thenReturn(lockoutMode);

        // Lockout is not considered an error for BiometricManager#canAuthenticate
        assertEquals(BiometricManager.BIOMETRIC_ERROR_LOCKOUT,
                invokeCanAuthenticate(mBiometricService, Authenticators.BIOMETRIC_STRONG));
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
    public void testCanAuthenticate_whenMandatoryBiometricsRequested()
@@ -1529,7 +1560,7 @@ public class BiometricServiceTest {

        when(mTrustManager.isInSignificantPlace()).thenReturn(true);

        assertEquals(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
        assertEquals(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE,
                invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS));
    }

@@ -1572,7 +1603,7 @@ public class BiometricServiceTest {

        setupAuthForOnly(TYPE_CREDENTIAL, Authenticators.DEVICE_CREDENTIAL);

        assertEquals(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
        assertEquals(BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE,
                invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS));

        when(mTrustManager.isInSignificantPlace()).thenReturn(true);
Loading