From 23289ef7b6b96cbbe663b1eb5a1790d48b127ed0 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Wed, 28 Nov 2018 16:32:36 -0800 Subject: [PATCH] 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/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 --- Android.bp | 1 + .../hardware/biometrics/BiometricPrompt.java | 11 - .../biometrics/IBiometricServiceReceiver.aidl | 14 +- .../IBiometricServiceReceiverInternal.aidl | 41 +++ .../android/hardware/face/IFaceService.aidl | 4 +- .../fingerprint/IFingerprintService.aidl | 4 +- .../internal/statusbar/IStatusBar.aidl | 6 +- .../internal/statusbar/IStatusBarService.aidl | 6 +- core/res/res/values/strings.xml | 7 +- core/res/res/values/symbols.xml | 1 + .../SystemUI/res/layout/biometric_dialog.xml | 9 + packages/SystemUI/res/values/strings.xml | 2 + .../biometrics/BiometricDialogImpl.java | 68 +++- .../biometrics/BiometricDialogView.java | 55 ++- .../biometrics/DialogViewCallback.java | 5 + .../systemui/statusbar/CommandQueue.java | 24 +- .../biometrics/AuthenticationClient.java | 14 +- .../server/biometrics/BiometricService.java | 348 +++++++++++++----- .../biometrics/BiometricServiceBase.java | 26 +- .../server/biometrics/face/FaceService.java | 14 +- .../fingerprint/FingerprintService.java | 11 +- .../statusbar/StatusBarManagerService.java | 17 +- 22 files changed, 510 insertions(+), 178 deletions(-) create mode 100644 core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl diff --git a/Android.bp b/Android.bp index 8bce769694c8f..a3ab5942688b4 100644 --- a/Android.bp +++ b/Android.bp @@ -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", diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 3c7ba14e86f16..b238d778f55ab 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -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(() -> { diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl index 62222a398aff6..22ef33e86e175 100644 --- a/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl +++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl @@ -16,28 +16,16 @@ package android.hardware.biometrics; /** - * Communication channel from - * 1) BiometricDialogImpl (SysUI) back to BiometricService - * 2) Service back to BiometricService - * 3) BiometricService back to BiometricPrompt - * BiometricPrompt sends a receiver to BiometricService, BiometricService contains another - * "trampoline" receiver which intercepts messages from 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. diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl new file mode 100644 index 0000000000000..180daaf97adaa --- /dev/null +++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl @@ -0,0 +1,41 @@ +/* + * 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) 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(); +} diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index f17bfc48295ac..a15dcec3b2762 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -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. diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index b859720a5a280..dd6b29d87d678 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -15,7 +15,7 @@ */ package android.hardware.fingerprint; -import android.hardware.biometrics.IBiometricServiceReceiver; +import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.fingerprint.IFingerprintClientActiveCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; @@ -39,7 +39,7 @@ interface IFingerprintService { // by BiometricService. To start authentication after the clients are ready, use // startPreparedClient(). void prepareForAuthentication(IBinder token, long sessionId, int userId, - IBiometricServiceReceiver wrapperReceiver, String opPackageName, int cookie, + IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId); // Starts authentication with the previously prepared client. diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index bb009000f36d2..600b1b324257c 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -18,7 +18,7 @@ package com.android.internal.statusbar; import android.content.ComponentName; import android.graphics.Rect; -import android.hardware.biometrics.IBiometricServiceReceiver; +import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.os.Bundle; import android.service.notification.StatusBarNotification; @@ -141,7 +141,7 @@ oneway interface IStatusBar void showShutdownUi(boolean isReboot, String reason); // Used to show the dialog when BiometricService starts authentication - void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiver receiver, int type, + void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, boolean requireConfirmation, int userId); // Used to hide the dialog when a biometric is authenticated void onBiometricAuthenticated(); @@ -151,4 +151,6 @@ oneway interface IStatusBar void onBiometricError(String error); // Used to hide the biometric dialog when the AuthenticationClient is stopped void hideBiometricDialog(); + // Used to request the "try again" button for authentications which requireConfirmation=true + void showBiometricTryAgain(); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 40a781288ed3c..22cec176dd477 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -20,7 +20,7 @@ import android.content.ComponentName; import android.graphics.Rect; import android.os.Bundle; import android.service.notification.StatusBarNotification; -import android.hardware.biometrics.IBiometricServiceReceiver; +import android.hardware.biometrics.IBiometricServiceReceiverInternal; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; @@ -91,7 +91,7 @@ interface IStatusBarService void showPinningEscapeToast(); // Used to show the dialog when BiometricService starts authentication - void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiver receiver, int type, + void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, boolean requireConfirmation, int userId); // Used to hide the dialog when a biometric is authenticated void onBiometricAuthenticated(); @@ -101,4 +101,6 @@ interface IStatusBarService void onBiometricError(String error); // Used to hide the biometric dialog when the AuthenticationClient is stopped void hideBiometricDialog(); + // Used to request the "try again" button for authentications which requireConfirmation=true + void showBiometricTryAgain(); } diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d16df59744e23..98f591f9675c4 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1444,11 +1444,14 @@ Application %s wants to authenticate. - Biometric hardware unavailable Authentication canceled + + Not recognized + + Authentication canceled Partial fingerprint detected. Please try again. @@ -1464,8 +1467,6 @@ - - Not recognized Fingerprint authenticated diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 18b1206e7e0e4..7ab34aa1527fb 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2404,6 +2404,7 @@ + diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml index 5ca34b033f0d1..1e8cd5a7e13bf 100644 --- a/packages/SystemUI/res/layout/biometric_dialog.xml +++ b/packages/SystemUI/res/layout/biometric_dialog.xml @@ -160,6 +160,15 @@ android:maxLines="2" android:text="@string/biometric_dialog_confirm" android:visibility="gone"/> + +