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

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

1/n: Move BiometricDialog management to BiometricService

The BiometricDialog management was done in AuthenticationClient, but
this is not great for the following reasons
1) The dialog lifecycle should not be 1:1 tied to the client monitor,
   since this restricts flexibility
2) Devices with multiple biometrics implemented on BiometricDialog
   will require extra work. Moving the dialog management up one layer
   should solve this limitation

BiometricService now sends both its own receiver and the client's receiver
to the appropriate <Biometric>Service. When the client is actually started
by the <Biometric>Service, it will forward the client's (BiometricPrompt's)
receiver to BiometricService. Lifecycle management is currently still in
<Biometric>Service since the platform still uses <Biometric>Service
directly. AuthenticationClient for BP is now started with the wrapper
receiver, which allows BiometricService to handle messages before deciding
if it should forward the message to the client.

Moving lifecycle management to BiometricService is currently not a great
idea since framework doesn't always go through BiometricService.

Also merged IBiometricPromptReceiver with IBiometricServiceReceiver

Bug: 111461540

Test: Negative button works (error received by demo app)
Test: Cancelling via back or tapping gray area works (error received
      by demo app), and hardware is no longer authenticating
Test: Dismissing BP via negative button or gray area returns only a single
      error and is not followed by ERROR_CANCELED (as expected)
Test: Error messages are delayed when BP is showing, not delayed
      when BP is not showing (pre-auth check errors e.g. no hardware)
Test: Lockout works
Test: Lockout counter resets upon successful auth
Test: Keys are unlocked properly for both implicit and explicit modes

TODO: Figure out multi-modal BiometricService / <Biometric>Service
      synchronization. Likely we keep the bundle in BiometricService
      and send random numbers (identifier) to <Biometric>Service. When
      each <Biometric>Service is ready, it should return the number. Once
      BiometricService receives all identifiers, it can then notify
      all <Biometric>Service to start authenticating.

Change-Id: I2b6fa57ed3c3cbccc7b0be30279f80fa46a8e917
parent 2ca566b5
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -157,7 +157,6 @@ java_defaults {
        "core/java/android/hardware/IConsumerIrService.aidl",
        "core/java/android/hardware/ISerialManager.aidl",
        "core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl",
        "core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
        "core/java/android/hardware/biometrics/IBiometricService.aidl",
        "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
        "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
+3 −3
Original line number Diff line number Diff line
@@ -32,17 +32,17 @@ public interface BiometricAuthenticator {
    /**
     * @hide
     */
    int TYPE_FINGERPRINT = 1;
    int TYPE_FINGERPRINT = 1 << 0;

    /**
     * @hide
     */
    int TYPE_IRIS = 2;
    int TYPE_IRIS = 1 << 1;

    /**
     * @hide
     */
    int TYPE_FACE = 3;
    int TYPE_FACE = 1 << 2;

    /**
     * Container for biometric data
+27 −24
Original line number Diff line number Diff line
@@ -251,27 +251,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
    private Executor mExecutor;
    private AuthenticationCallback mAuthenticationCallback;

    IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
        @Override
        public void onDialogDismissed(int reason) {
            // Check the reason and invoke OnClickListener(s) if necessary
            if (reason == DISMISSED_REASON_POSITIVE) {
                mPositiveButtonInfo.executor.execute(() -> {
                    mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE);
                });
            } else if (reason == DISMISSED_REASON_NEGATIVE) {
                mNegativeButtonInfo.executor.execute(() -> {
                    mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE);
                });
            }
        }
    };

    IBiometricServiceReceiver mBiometricServiceReceiver =
    private final IBiometricServiceReceiver mBiometricServiceReceiver =
            new IBiometricServiceReceiver.Stub() {

        @Override
        public void onAuthenticationSucceeded(long deviceId) throws RemoteException {
        public void onAuthenticationSucceeded() throws RemoteException {
            mExecutor.execute(() -> {
                final AuthenticationResult result = new AuthenticationResult(mCryptoObject);
                mAuthenticationCallback.onAuthenticationSucceeded(result);
@@ -279,14 +263,20 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        }

        @Override
        public void onAuthenticationFailed(long deviceId) throws RemoteException {
        public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] bytes)
                throws RemoteException {
            throw new UnsupportedOperationException("Operation not supported!");
        }

        @Override
        public void onAuthenticationFailed() throws RemoteException {
            mExecutor.execute(() -> {
                mAuthenticationCallback.onAuthenticationFailed();
            });
        }

        @Override
        public void onError(long deviceId, int error, String message)
        public void onError(int error, String message)
                throws RemoteException {
            mExecutor.execute(() -> {
                mAuthenticationCallback.onAuthenticationError(error, message);
@@ -294,11 +284,25 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
        }

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

        @Override
        public void onDialogDismissed(int reason) {
            // Check the reason and invoke OnClickListener(s) if necessary
            if (reason == DISMISSED_REASON_POSITIVE) {
                mPositiveButtonInfo.executor.execute(() -> {
                    mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE);
                });
            } else if (reason == DISMISSED_REASON_NEGATIVE) {
                mNegativeButtonInfo.executor.execute(() -> {
                    mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE);
                });
            }
        }
    };

    private BiometricPrompt(Context context, Bundle bundle,
@@ -557,9 +561,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            mExecutor = executor;
            mAuthenticationCallback = callback;
            final long sessionId = crypto != null ? crypto.getOpId() : 0;
            mService.authenticate(mToken, sessionId, userId,
                    mBiometricServiceReceiver, 0 /* flags */, mContext.getOpPackageName(),
                    mBundle, mDialogReceiver);
            mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
                    0 /* flags */, mContext.getOpPackageName(), mBundle);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception while authenticating", e);
            mExecutor.execute(() -> {
+0 −24
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.hardware.biometrics;

/**
 * Communication channel from the BiometricPrompt (SysUI) back to AuthenticationClient.
 * @hide
 */
oneway interface IBiometricPromptReceiver {
    void onDialogDismissed(int reason);
}
+6 −3
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package android.hardware.biometrics;

import android.os.Bundle;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricPromptReceiver;
import android.hardware.biometrics.IBiometricServiceReceiver;

/**
@@ -32,8 +31,7 @@ interface IBiometricService {
    // Requests authentication. The service choose the appropriate biometric to use, and show
    // the corresponding BiometricDialog.
    void authenticate(IBinder token, long sessionId, int userId,
            IBiometricServiceReceiver receiver, int flags, String opPackageName,
            in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
            IBiometricServiceReceiver receiver, int flags, String opPackageName, in Bundle bundle);

    // Cancel authentication for the given sessionId
    void cancelAuthentication(IBinder token, String opPackageName);
@@ -46,4 +44,9 @@ interface IBiometricService {

    // Explicitly set the active user.
    void setActiveUser(int userId);

    // Notify BiometricService when <Biometric>Service starts a new client. Client lifecycle
    // is still managed in <Biometric>Service.
    void onAuthenticationStarted(in Bundle bundle, IBiometricServiceReceiver receiver, int type,
            boolean requireConfirmation, int userId);
}
Loading