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

Commit 23289ef7 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

3/n: For passive modalities, add plumbing for "try again"

When "try again" is showing, authentication is canceled internally.
BiometricService caches the client's info so that authentication can
be restarted when "try again" is pressed. Because authentication
is not running when "try again" is showing, BiometricService also needs
to have a TaskStackListener so that BP can be dismissed and an error can
be sent to the client when the app loses focus.

IBiometricServiceReceiver has been split into two. One for BiometricPrompt
to receive messages from BiometricService, and another for BiometricService
to receive messages from SystemUI/<Biometric>Services.

When we get locked out, don't send the last onAuthenticationFailed
to the client, since "Authentication failed" will be shown briefly
and be replaced by "Device locked out" which is janky

Bug: 111461540

Test: Tested with requireConfirmation enabled/disabled
Test: Tested onConfigurationChange corner cases, e.g. when "try again"
      or "confirm" buttons are showing, rotate the device. Buttons
      persist correctly and don't appear when unexpected
Test: Tested task stack corner cases, e.g. when "try again" is showing,
      press home button. BP dismisses and client receives ERROR_CANCELED
Test: BiometricPromptDemo receives all callbacks

Change-Id: I62126708ce8db8b358c666a07aa7c39607642c9d
parent 87f257a9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ java_defaults {
        "core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl",
        "core/java/android/hardware/biometrics/IBiometricService.aidl",
        "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
        "core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl",
        "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
        "core/java/android/hardware/display/IDisplayManager.aidl",
        "core/java/android/hardware/display/IDisplayManagerCallback.aidl",
+0 −11
Original line number Diff line number Diff line
@@ -262,12 +262,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            });
        }

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

        @Override
        public void onAuthenticationFailed() throws RemoteException {
            mExecutor.execute(() -> {
@@ -282,11 +276,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
            });
        }

        @Override
        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(() -> {
+1 −13
Original line number Diff line number Diff line
@@ -16,28 +16,16 @@
package android.hardware.biometrics;

/**
 * Communication channel from
 *   1) BiometricDialogImpl (SysUI) back to BiometricService
 *   2) <Biometric>Service back to BiometricService
 *   3) BiometricService back to BiometricPrompt
 * BiometricPrompt sends a receiver to BiometricService, BiometricService contains another
 * "trampoline" receiver which intercepts messages from <Biometric>Service and does some
 * logic before forwarding results as necessary to BiometricPrompt.
 * Communication channel from BiometricService back to BiometricPrompt
 * @hide
 */
oneway interface IBiometricServiceReceiver {
    // Notify BiometricPrompt that authentication was successful
    void onAuthenticationSucceeded();
    // Notify BiometricService that authentication was successful. If user confirmation is required,
    // the auth token must be submitted into KeyStore.
    void onAuthenticationSucceededInternal(boolean requireConfirmation, in byte[] token);
    // Noties that authentication failed.
    void onAuthenticationFailed();
    // Notify BiometricPrompt that an error has occurred.
    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.
    void onAcquired(int acquiredInfo, String message);
    // Notifies that the SystemUI dialog has been dismissed.
+41 −0
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
 *   1) BiometricDialogImpl (SysUI) back to BiometricService
 *   2) <Biometric>Service back to BiometricService
 * Receives messages from the above and does some handling before forwarding to BiometricPrompt
 * via IBiometricServiceReceiver.
 * @hide
 */
oneway interface IBiometricServiceReceiverInternal {
    // Notify BiometricService that authentication was successful. If user confirmation is required,
    // the auth token must be submitted into KeyStore.
    void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token);
    // Notify BiometricService that an error has occurred.
    void onAuthenticationFailed(int cookie, boolean requireConfirmation);
    // Notify BiometricService than an error has occured. Forward to the correct receiver depending
    // on the cookie.
    void onError(int cookie, int error, String message);
    // Notifies that a biometric has been acquired.
    void onAcquired(int acquiredInfo, String message);
    // Notifies that the SystemUI dialog has been dismissed.
    void onDialogDismissed(int reason);
    // Notifies that the user has pressed the "try again" button on SystemUI
    void onTryAgainPressed();
}
+2 −2
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
 */
package android.hardware.face;

import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
@@ -36,7 +36,7 @@ interface IFaceService {
    // by BiometricService. To start authentication after the clients are ready, use
    // startPreparedClient().
    void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId,
            int userId, IBiometricServiceReceiver wrapperReceiver, String opPackageName,
            int userId, IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName,
            int cookie, int callingUid, int callingPid, int callingUserId);

    // Starts authentication with the previously prepared client.
Loading