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

Commit dbe67876 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

20/n: Update infrastructure to support upcoming scheduler

1) Templates ClientMonitor<T>, so that redundant code can be removed
2) Moves ClientMonitor and subclass's HAL reference and FinishCallback
   to be initialized in ClientMonitor#start. This allows the logic
   to be centralied in the upcoming scheduler (e.g. HAL availability
   check, having the scheduler use an internal FinishCallback, etc)
3) Moved HAL null-checking to a centralized location. As such, also
   added abstract ClientMonitor#unableToStart method, which is invoked
   when the ClientMonitor can't/shouldn't be started. Each subclass
   handles this case individually based on its own API lifecycle
4) Added BiometricAuthenticator interface to query current lockout mode.
   Looks like BiometricService was relying on receiving onError(lockout)
   being sent before onReadyForAuthentication. However, to clean up the
   FingerprintService/FaceService code and move client lifecycle into
   ClientMonitor, we shouldn't rely on this ordering.

Note that this change also makes BiometricServiceBase templated solely
for the purpose of getting a reference to the biometric HAL. This is
a little ugly. This is temporary and will only exist during the middle
of the refactor. By the end of the refactor, BiometricServiceBase will
be gone/deleted, and we should end up with a Scheduler<T> :)

Bug: 157790417

Test: Enroll, authenticate, resetLockout, set/getFeature in settings,
      internal cleanup (modifying fingerprint/face utils), for
      fingerprint and face, and for multi-user/profile
Test: Lockout user, then request authenticate again. Notice no vibration,
      no UI, and correct error result
Test: Lockout user, then request auth with biometric|credential.
      Credential UI is shown immediately.
Test: Lockout user, then check canAuthenticate. Returns success, since
      the hardware is OK, just the user was rejected too many times.
      Note that this is functionally the same as before, since the
      sensor would have been considered eligible.
Test: atest com.android.server.biometrics

Change-Id: I420002d2b54a4ab530d0698fcc612ee7c770d5ff
parent 11e1f825
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -50,6 +50,9 @@ interface IBiometricAuthenticator {
    // Determine if a user has at least one enrolled face
    boolean hasEnrolledTemplates(int userId, String opPackageName);

    // Return the LockoutTracker status for the specified user
    int getLockoutModeForUser(int userId);

    // Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
    void resetLockout(int userId, in byte [] hardwareAuthToken);

+3 −0
Original line number Diff line number Diff line
@@ -80,6 +80,9 @@ interface IFaceService {
    // Determine if a user has at least one enrolled face
    boolean hasEnrolledFaces(int userId, String opPackageName);

    // Return the LockoutTracker status for the specified user
    int getLockoutModeForUser(int userId);

    // Gets the authenticator ID for face
    long getAuthenticatorId(int callingUserId);

+3 −0
Original line number Diff line number Diff line
@@ -84,6 +84,9 @@ interface IFingerprintService {
    // Determine if a user has at least one enrolled fingerprint
    boolean hasEnrolledFingerprints(int userId, String opPackageName);

    // Return the LockoutTracker status for the specified user
    int getLockoutModeForUser(int userId);

    // Gets the authenticator ID for fingerprint
    long getAuthenticatorId(int callingUserId);

+28 −11
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ import android.os.RemoteException;
import android.util.Pair;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.sensors.LockoutTracker;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -54,6 +57,8 @@ class PreAuthInfo {
    static final int BIOMETRIC_NOT_ENROLLED = 7;
    static final int BIOMETRIC_NOT_ENABLED_FOR_APPS = 8;
    static final int CREDENTIAL_NOT_ENROLLED = 9;
    static final int BIOMETRIC_LOCKOUT_TIMED = 10;
    static final int BIOMETRIC_LOCKOUT_PERMANENT = 11;
    @IntDef({AUTHENTICATOR_OK,
            BIOMETRIC_NO_HARDWARE,
            BIOMETRIC_DISABLED_BY_DEVICE_POLICY,
@@ -62,7 +67,9 @@ class PreAuthInfo {
            BIOMETRIC_HARDWARE_NOT_DETECTED,
            BIOMETRIC_NOT_ENROLLED,
            BIOMETRIC_NOT_ENABLED_FOR_APPS,
            CREDENTIAL_NOT_ENROLLED})
            CREDENTIAL_NOT_ENROLLED,
            BIOMETRIC_LOCKOUT_TIMED,
            BIOMETRIC_LOCKOUT_PERMANENT})
    @Retention(RetentionPolicy.SOURCE)
    @interface AuthenticatorStatus {}

@@ -73,7 +80,7 @@ class PreAuthInfo {
    // Sensors that can be used for this request (e.g. strong enough, enrolled, enabled).
    final List<BiometricSensor> eligibleSensors;
    // Sensors that cannot be used for this request. Pair<BiometricSensor, AuthenticatorStatus>
    private final List<Pair<BiometricSensor, Integer>> mIneligibleSensors;
    final List<Pair<BiometricSensor, Integer>> ineligibleSensors;
    final boolean credentialAvailable;
    final boolean confirmationRequested;

@@ -156,6 +163,14 @@ class PreAuthInfo {
            if (!sensor.impl.hasEnrolledTemplates(userId, opPackageName)) {
                return BIOMETRIC_NOT_ENROLLED;
            }

            final @LockoutTracker.LockoutMode int lockoutMode =
                    sensor.impl.getLockoutModeForUser(userId);
            if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) {
                return BIOMETRIC_LOCKOUT_TIMED;
            } else if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) {
                return BIOMETRIC_LOCKOUT_PERMANENT;
            }
        } catch (RemoteException e) {
            return BIOMETRIC_HARDWARE_NOT_DETECTED;
        }
@@ -232,7 +247,7 @@ class PreAuthInfo {
        this.credentialRequested = credentialRequested;

        this.eligibleSensors = eligibleSensors;
        this.mIneligibleSensors = ineligibleSensors;
        this.ineligibleSensors = ineligibleSensors;
        this.credentialAvailable = credentialAvailable;
        this.confirmationRequested = confirmationRequested;
    }
@@ -258,9 +273,9 @@ class PreAuthInfo {
                }
            } else {
                // Pick the first sensor error if it exists
                if (!mIneligibleSensors.isEmpty()) {
                    modality |= mIneligibleSensors.get(0).first.modality;
                    status = mIneligibleSensors.get(0).second;
                if (!ineligibleSensors.isEmpty()) {
                    modality |= ineligibleSensors.get(0).first.modality;
                    status = ineligibleSensors.get(0).second;
                } else {
                    modality |= TYPE_CREDENTIAL;
                    status = CREDENTIAL_NOT_ENROLLED;
@@ -274,9 +289,9 @@ class PreAuthInfo {
                 }
            } else {
                // Pick the first sensor error if it exists
                if (!mIneligibleSensors.isEmpty()) {
                    modality |= mIneligibleSensors.get(0).first.modality;
                    status = mIneligibleSensors.get(0).second;
                if (!ineligibleSensors.isEmpty()) {
                    modality |= ineligibleSensors.get(0).first.modality;
                    status = ineligibleSensors.get(0).second;
                } else {
                    modality |= TYPE_NONE;
                    status = BIOMETRIC_NO_HARDWARE;
@@ -293,7 +308,7 @@ class PreAuthInfo {
        }

        Slog.d(TAG, "getCanAuthenticateInternal Modality: " + modality
                + " AuthenticatorSatus: " + status);
                + " AuthenticatorStatus: " + status);
        return new Pair<>(modality, status);
    }

@@ -325,6 +340,8 @@ class PreAuthInfo {
            case BIOMETRIC_HARDWARE_NOT_DETECTED:
            case BIOMETRIC_NOT_ENROLLED:
            case CREDENTIAL_NOT_ENROLLED:
            case BIOMETRIC_LOCKOUT_TIMED:
            case BIOMETRIC_LOCKOUT_PERMANENT:
                break;

            case BIOMETRIC_DISABLED_BY_DEVICE_POLICY:
@@ -379,7 +396,7 @@ class PreAuthInfo {
        string.append("}");

        string.append("\nIneligible:{");
        for (Pair<BiometricSensor, Integer> ineligible : mIneligibleSensors) {
        for (Pair<BiometricSensor, Integer> ineligible : ineligibleSensors) {
            string.append(ineligible.first).append(":").append(ineligible.second).append(" ");
        }
        string.append("}");
+12 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_DISABLED_BY_DE
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_HARDWARE_NOT_DETECTED;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_INSUFFICIENT_STRENGTH;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_LOCKOUT_PERMANENT;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_LOCKOUT_TIMED;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NOT_ENABLED_FOR_APPS;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NOT_ENROLLED;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NO_HARDWARE;
@@ -235,6 +237,10 @@ public class Utils {
            case BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
                biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED;
                break;
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
                biometricManagerCode = BiometricManager.BIOMETRIC_SUCCESS;
                break;
            default:
                Slog.e(BiometricService.TAG, "Unhandled result code: " + biometricConstantsCode);
                biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
@@ -289,6 +295,12 @@ public class Utils {
            case CREDENTIAL_NOT_ENROLLED:
                return BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL;

            case BIOMETRIC_LOCKOUT_TIMED:
                return BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;

            case BIOMETRIC_LOCKOUT_PERMANENT:
                return BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;

            case BIOMETRIC_DISABLED_BY_DEVICE_POLICY:
            case BIOMETRIC_HARDWARE_NOT_DETECTED:
            case BIOMETRIC_NOT_ENABLED_FOR_APPS:
Loading