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

Commit 87f257a9 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

2/n: Multi-modal support for BiometricPrompt

Part 2 of decoupling BiometricDialog lifecycle from AuthenticationClient
lifecycle. This change introduces cookies which are used to keep track
of clients within BiometricService and <Biometric>Services. This allows

1) Much easier support for BiometricPrompt to authenticate using more than
   one modality
2) Much easier to support "continue" button on BiometricPrompt for passive
   modalities, which should be pressed before authentication continues

Bug: 111461540

Test: BiometricPromptDemo works, error messages are propagated to clients
Test: Keyguard/Settings smoke test
Test: ConfirmDeviceCredentials works

Change-Id: Iaa246488fb027c3397a3191841524b389145b281
parent e92cdae2
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -30,16 +30,26 @@ import java.util.concurrent.Executor;
public interface BiometricAuthenticator {
public interface BiometricAuthenticator {


    /**
    /**
     * No biometric methods or nothing has been enrolled.
     * Move/expose these in BiometricPrompt if we ever want to allow applications to "blacklist"
     * modalities when calling authenticate().
     * @hide
     */
    int TYPE_NONE = 0;
    /**
     * Constant representing fingerprint.
     * @hide
     * @hide
     */
     */
    int TYPE_FINGERPRINT = 1 << 0;
    int TYPE_FINGERPRINT = 1 << 0;


    /**
    /**
     * Constant representing iris.
     * @hide
     * @hide
     */
     */
    int TYPE_IRIS = 1 << 1;
    int TYPE_IRIS = 1 << 1;


    /**
    /**
     * Constant representing face.
     * @hide
     * @hide
     */
     */
    int TYPE_FACE = 1 << 2;
    int TYPE_FACE = 1 << 2;
+9 −5
Original line number Original line Diff line number Diff line
@@ -276,22 +276,26 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        }
        }


        @Override
        @Override
        public void onError(int error, String message)
        public void onError(int error, String message) throws RemoteException {
                throws RemoteException {
            mExecutor.execute(() -> {
            mExecutor.execute(() -> {
                mAuthenticationCallback.onAuthenticationError(error, message);
                mAuthenticationCallback.onAuthenticationError(error, message);
            });
            });
        }
        }


        @Override
        @Override
        public void onAcquired(int acquireInfo, String message) {
        public void onErrorInternal(int error, String message, int cookie) throws RemoteException {
            throw new UnsupportedOperationException("Operation not supported!");
        }

        @Override
        public void onAcquired(int acquireInfo, String message) throws RemoteException {
            mExecutor.execute(() -> {
            mExecutor.execute(() -> {
                mAuthenticationCallback.onAuthenticationHelp(acquireInfo, message);
                mAuthenticationCallback.onAuthenticationHelp(acquireInfo, message);
            });
            });
        }
        }


        @Override
        @Override
        public void onDialogDismissed(int reason) {
        public void onDialogDismissed(int reason) throws RemoteException {
            // Check the reason and invoke OnClickListener(s) if necessary
            // Check the reason and invoke OnClickListener(s) if necessary
            if (reason == DISMISSED_REASON_POSITIVE) {
            if (reason == DISMISSED_REASON_POSITIVE) {
                mPositiveButtonInfo.executor.execute(() -> {
                mPositiveButtonInfo.executor.execute(() -> {
@@ -562,7 +566,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            mAuthenticationCallback = callback;
            mAuthenticationCallback = callback;
            final long sessionId = crypto != null ? crypto.getOpId() : 0;
            final long sessionId = crypto != null ? crypto.getOpId() : 0;
            mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
            mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
                    0 /* flags */, mContext.getOpPackageName(), mBundle);
                    mContext.getOpPackageName(), mBundle);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception while authenticating", e);
            Log.e(TAG, "Remote exception while authenticating", e);
            mExecutor.execute(() -> {
            mExecutor.execute(() -> {
+4 −5
Original line number Original line Diff line number Diff line
@@ -31,7 +31,7 @@ interface IBiometricService {
    // Requests authentication. The service choose the appropriate biometric to use, and show
    // Requests authentication. The service choose the appropriate biometric to use, and show
    // the corresponding BiometricDialog.
    // the corresponding BiometricDialog.
    void authenticate(IBinder token, long sessionId, int userId,
    void authenticate(IBinder token, long sessionId, int userId,
            IBiometricServiceReceiver receiver, int flags, String opPackageName, in Bundle bundle);
            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle);


    // Cancel authentication for the given sessionId
    // Cancel authentication for the given sessionId
    void cancelAuthentication(IBinder token, String opPackageName);
    void cancelAuthentication(IBinder token, String opPackageName);
@@ -45,8 +45,7 @@ interface IBiometricService {
    // Explicitly set the active user.
    // Explicitly set the active user.
    void setActiveUser(int userId);
    void setActiveUser(int userId);


    // Notify BiometricService when <Biometric>Service starts a new client. Client lifecycle
    // Notify BiometricService when <Biometric>Service is ready to start the prepared client.
    // is still managed in <Biometric>Service.
    // Client lifecycle is still managed in <Biometric>Service.
    void onAuthenticationStarted(in Bundle bundle, IBiometricServiceReceiver receiver, int type,
    void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId);
            boolean requireConfirmation, int userId);
}
}
+4 −1
Original line number Original line Diff line number Diff line
@@ -33,8 +33,11 @@ oneway interface IBiometricServiceReceiver {
    void onAuthenticationSucceededInternal(boolean requireConfirmation, in byte[] token);
    void onAuthenticationSucceededInternal(boolean requireConfirmation, in byte[] token);
    // Noties that authentication failed.
    // Noties that authentication failed.
    void onAuthenticationFailed();
    void onAuthenticationFailed();
    // Notifies that an error has occurred.
    // Notify BiometricPrompt that an error has occurred.
    void onError(int error, String message);
    void onError(int error, String message);
    // Notify BiometricService than an error has occured. Forward to the correct receiver depending
    // on the cookie.
    void onErrorInternal(int error, String message, int cookie);
    // Notifies that a biometric has been acquired.
    // Notifies that a biometric has been acquired.
    void onAcquired(int acquiredInfo, String message);
    void onAcquired(int acquiredInfo, String message);
    // Notifies that the SystemUI dialog has been dismissed.
    // Notifies that the SystemUI dialog has been dismissed.
+11 −7
Original line number Original line Diff line number Diff line
@@ -15,7 +15,6 @@
 */
 */
package android.hardware.face;
package android.hardware.face;


import android.os.Bundle;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.IFaceServiceReceiver;
@@ -31,12 +30,17 @@ interface IFaceService {
    void authenticate(IBinder token, long sessionId,
    void authenticate(IBinder token, long sessionId,
            IFaceServiceReceiver receiver, int flags, String opPackageName);
            IFaceServiceReceiver receiver, int flags, String opPackageName);


    // This method invokes the BiometricDialog. The arguments are almost the same as above,
    // This method prepares the service to start authenticating, but doesn't start authentication.
    // but should only be called from (BiometricPromptService).
    // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
    void authenticateFromService(boolean requireConfirmation, IBinder token, long sessionId,
    // called from BiometricService. The additional uid, pid, userId arguments should be determined
            int userId, IBiometricServiceReceiver clientRceiver,
    // by BiometricService. To start authentication after the clients are ready, use
            IBiometricServiceReceiver wrapperReceiver, int flags, String opPackageName,
    // startPreparedClient().
            in Bundle bundle, int callingUid, int callingPid, int callingUserId);
    void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId,
            int userId, IBiometricServiceReceiver wrapperReceiver, String opPackageName,
            int cookie, int callingUid, int callingPid, int callingUserId);

    // Starts authentication with the previously prepared client.
    void startPreparedClient(int cookie);


    // Cancel authentication for the given sessionId
    // Cancel authentication for the given sessionId
    void cancelAuthentication(IBinder token, String opPackageName);
    void cancelAuthentication(IBinder token, String opPackageName);
Loading