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

Commit b01cc001 authored by Joe Bolinger's avatar Joe Bolinger
Browse files

Add BiometricPrompt implementation with class 3 support.

This is a prerequisite change to restore the delayed fingerprint sensor logic that was removed when strong coex support was postponed last year.

It is not used in the new flagged BIOMETRIC_BP_STRONG SysUI code, but can not easily be flagged and potentially impacts both implementations. This cl is not standalone and requires the corresponding SysUI changes in the topic.

Bug: 272510026
Bug: 251476085
Test: atest AuthSessionTest BiometricServiceTest
Test: manual (see other cls in topic)
Change-Id: I474329496c87bcbedfff43024d8c3bfde7824dd7
parent e61670d5
Loading
Loading
Loading
Loading
+0 −21
Original line number Diff line number Diff line
@@ -96,27 +96,6 @@ public class BiometricManager {
    @Retention(RetentionPolicy.SOURCE)
    public @interface BiometricError {}

    /**
     * Single sensor or unspecified multi-sensor behavior (prefer an explicit choice if the
     * device is multi-sensor).
     * @hide
     */
    public static final int BIOMETRIC_MULTI_SENSOR_DEFAULT = 0;

    /**
     * Use face and fingerprint sensors together.
     * @hide
     */
    public static final int BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE = 1;

    /**
     * @hide
     */
    @IntDef({BIOMETRIC_MULTI_SENSOR_DEFAULT,
            BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface BiometricMultiSensorMode {}

    /**
     * Types of authenticators, defined at a level of granularity supported by
     * {@link BiometricManager} and {@link BiometricPrompt}.
+3 −1
Original line number Diff line number Diff line
@@ -29,5 +29,7 @@ oneway interface IBiometricSysuiReceiver {
    // Notifies the client that an internal event, e.g. back button has occurred.
    void onSystemEvent(int event);
    // Notifies that the dialog has finished animating.
    void onDialogAnimatedIn();
    void onDialogAnimatedIn(boolean startFingerprintNow);
    // Notifies that the fingerprint should start now (after onDialogAnimatedIn(false)).
    void onStartFingerprintNow();
}
+1 −1
Original line number Diff line number Diff line
@@ -157,7 +157,7 @@ oneway interface IStatusBar
    */
    void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
            in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
            long operationId, String opPackageName, long requestId, int multiSensorConfig);
            long operationId, String opPackageName, long requestId);
    /**
    * Used to notify the authentication dialog that a biometric has been authenticated.
    */
+1 −2
Original line number Diff line number Diff line
@@ -123,8 +123,7 @@ interface IStatusBarService
    // Used to show the authentication dialog (Biometrics, Device Credential)
    void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
            in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
            int userId, long operationId, String opPackageName, long requestId,
            int multiSensorConfig);
            int userId, long operationId, String opPackageName, long requestId);

    // Used to notify the authentication dialog that a biometric has been authenticated
    void onBiometricAuthenticated(int modality);
+21 −35
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR_BASE;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE;

import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
@@ -44,7 +42,6 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -68,7 +65,6 @@ import com.android.server.biometrics.log.OperationContextExt;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
@@ -134,7 +130,6 @@ public final class AuthSession implements IBinder.DeathRecipient {

    // The current state, which can be either idle, called, or started
    private @SessionState int mState = STATE_AUTH_IDLE;
    private @BiometricMultiSensorMode int mMultiSensorMode;
    private int[] mSensors;
    // TODO(b/197265902): merge into state
    private boolean mCancelled;
@@ -255,7 +250,6 @@ public final class AuthSession implements IBinder.DeathRecipient {
            // SystemUI invokes that path.
            mState = STATE_SHOWING_DEVICE_CREDENTIAL;
            mSensors = new int[0];
            mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT;

            mStatusBarService.showAuthenticationDialog(
                    mPromptInfo,
@@ -266,8 +260,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
                    mUserId,
                    mOperationId,
                    mOpPackageName,
                    mRequestId,
                    mMultiSensorMode);
                    mRequestId);
        } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) {
            // Some combination of biometric or biometric|credential is requested
            setSensorsToStateWaitingForCookie(false /* isTryAgain */);
@@ -310,8 +303,6 @@ public final class AuthSession implements IBinder.DeathRecipient {
                    for (int i = 0; i < mPreAuthInfo.eligibleSensors.size(); i++) {
                        mSensors[i] = mPreAuthInfo.eligibleSensors.get(i).id;
                    }
                    mMultiSensorMode = getMultiSensorModeForNewSession(
                            mPreAuthInfo.eligibleSensors);

                    mStatusBarService.showAuthenticationDialog(mPromptInfo,
                            mSysuiReceiver,
@@ -321,8 +312,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
                            mUserId,
                            mOperationId,
                            mOpPackageName,
                            mRequestId,
                            mMultiSensorMode);
                            mRequestId);
                    mState = STATE_AUTH_STARTED;
                } catch (RemoteException e) {
                    Slog.e(TAG, "Remote exception", e);
@@ -438,7 +428,6 @@ public final class AuthSession implements IBinder.DeathRecipient {
                    mPromptInfo.setAuthenticators(authenticators);

                    mState = STATE_SHOWING_DEVICE_CREDENTIAL;
                    mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT;
                    mSensors = new int[0];

                    mStatusBarService.showAuthenticationDialog(
@@ -450,8 +439,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
                            mUserId,
                            mOperationId,
                            mOpPackageName,
                            mRequestId,
                            mMultiSensorMode);
                            mRequestId);
                } else {
                    mClientReceiver.onError(modality, error, vendorCode);
                    return true;
@@ -545,13 +533,30 @@ public final class AuthSession implements IBinder.DeathRecipient {
        }
    }

    void onDialogAnimatedIn() {
    void onDialogAnimatedIn(boolean startFingerprintNow) {
        if (mState != STATE_AUTH_STARTED) {
            Slog.e(TAG, "onDialogAnimatedIn, unexpected state: " + mState);
            return;
        }

        mState = STATE_AUTH_STARTED_UI_SHOWING;
        if (startFingerprintNow) {
            startAllPreparedFingerprintSensors();
        } else {
            Slog.d(TAG, "delaying fingerprint sensor start");
        }
    }

    // call once anytime after onDialogAnimatedIn() to indicate it's appropriate to start the
    // fingerprint sensor (i.e. face auth has failed or is not available)
    void onStartFingerprint() {
        if (mState != STATE_AUTH_STARTED
                && mState != STATE_AUTH_STARTED_UI_SHOWING
                && mState != STATE_AUTH_PAUSED
                && mState != STATE_ERROR_PENDING_SYSUI) {
            Slog.w(TAG, "onStartFingerprint, started from unexpected state: " + mState);
        }

        startAllPreparedFingerprintSensors();
    }

@@ -919,25 +924,6 @@ public final class AuthSession implements IBinder.DeathRecipient {
        }
    }

    @BiometricMultiSensorMode
    private static int getMultiSensorModeForNewSession(Collection<BiometricSensor> sensors) {
        boolean hasFace = false;
        boolean hasFingerprint = false;

        for (BiometricSensor sensor: sensors) {
            if (sensor.modality == TYPE_FACE) {
                hasFace = true;
            } else if (sensor.modality == TYPE_FINGERPRINT) {
                hasFingerprint = true;
            }
        }

        if (hasFace && hasFingerprint) {
            return BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE;
        }
        return BIOMETRIC_MULTI_SENSOR_DEFAULT;
    }

    @Override
    public String toString() {
        return "State: " + mState
Loading