diff options
46 files changed, 915 insertions, 687 deletions
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl index 4a46972cd200..8eb22dabbf3c 100644 --- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl +++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl @@ -50,6 +50,9 @@ interface IBiometricAuthenticator { // Determine if a user has at least one enrolled face boolean hasEnrolledTemplates(int userId, String opPackageName); + // Return the LockoutTracker status for the specified user + int getLockoutModeForUser(int userId); + // Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password) void resetLockout(int userId, in byte [] hardwareAuthToken); diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 9876de11a2bb..58cb1e135350 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -165,7 +165,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * * @param crypto object associated with the call or null if none required. * @param cancel an object that can be used to cancel authentication - * @param flags optional flags; should be 0 * @param callback an object to receive authentication events * @param handler an optional handler to handle callback events * @throws IllegalArgumentException if the crypto operation is not supported or is not backed @@ -177,8 +176,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { - authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId()); + @NonNull AuthenticationCallback callback, @Nullable Handler handler) { + authenticate(crypto, cancel, callback, handler, mContext.getUserId()); } /** @@ -202,7 +201,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * * @param crypto object associated with the call or null if none required. * @param cancel an object that can be used to cancel authentication - * @param flags optional flags; should be 0 * @param callback an object to receive authentication events * @param handler an optional handler to handle callback events * @param userId userId to authenticate for @@ -214,8 +212,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler, - int userId) { + @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } @@ -237,7 +234,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan final long operationId = crypto != null ? crypto.getOpId() : 0; Trace.beginSection("FaceManager#authenticate"); mService.authenticate(mToken, operationId, userId, mServiceReceiver, - flags, mContext.getOpPackageName()); + mContext.getOpPackageName()); } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); if (callback != null) { @@ -260,9 +257,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[], Surface) */ @RequiresPermission(MANAGE_BIOMETRIC) - public void enroll(int userId, byte[] token, CancellationSignal cancel, + public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, EnrollmentCallback callback, int[] disabledFeatures) { - enroll(userId, token, cancel, callback, disabledFeatures, null /* surface */); + enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures, null /* surface */); } /** @@ -277,7 +274,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @param token a unique token provided by a recent creation or verification of device * credentials (e.g. pin, pattern or password). * @param cancel an object that can be used to cancel enrollment - * @param flags optional flags * @param userId the user to whom this face will belong to * @param callback an object to receive enrollment events * @param surface optional camera preview surface for a single-camera device. Must be null if @@ -285,7 +281,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) - public void enroll(int userId, byte[] token, CancellationSignal cancel, + public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface surface) { if (callback == null) { throw new IllegalArgumentException("Must supply an enrollment callback"); @@ -304,7 +300,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan try { mEnrollmentCallback = callback; Trace.beginSection("FaceManager#enroll"); - mService.enroll(userId, mToken, token, mServiceReceiver, + mService.enroll(userId, mToken, hardwareAuthToken, mServiceReceiver, mContext.getOpPackageName(), disabledFeatures, surface); } catch (RemoteException e) { Slog.w(TAG, "Remote exception in enroll: ", e); @@ -329,15 +325,15 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * which point the object is no longer valid. The operation can be canceled by using the * provided cancel object. * - * @param token a unique token provided by a recent creation or verification of device - * credentials (e.g. pin, pattern or password). + * @param hardwareAuthToken a unique token provided by a recent creation or verification of + * device credentials (e.g. pin, pattern or password). * @param cancel an object that can be used to cancel enrollment * @param userId the user to whom this face will belong to * @param callback an object to receive enrollment events * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) - public void enrollRemotely(int userId, byte[] token, CancellationSignal cancel, + public void enrollRemotely(int userId, byte[] hardwareAuthToken, CancellationSignal cancel, EnrollmentCallback callback, int[] disabledFeatures) { if (callback == null) { throw new IllegalArgumentException("Must supply an enrollment callback"); @@ -356,7 +352,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan try { mEnrollmentCallback = callback; Trace.beginSection("FaceManager#enrollRemotely"); - mService.enrollRemotely(userId, mToken, token, mServiceReceiver, + mService.enrollRemotely(userId, mToken, hardwareAuthToken, mServiceReceiver, mContext.getOpPackageName(), disabledFeatures); } catch (RemoteException e) { Slog.w(TAG, "Remote exception in enrollRemotely: ", e); @@ -444,13 +440,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) - public void setFeature(int userId, int feature, boolean enabled, byte[] token, + public void setFeature(int userId, int feature, boolean enabled, byte[] hardwareAuthToken, SetFeatureCallback callback) { if (mService != null) { try { mSetFeatureCallback = callback; - mService.setFeature(userId, feature, enabled, token, mServiceReceiver, - mContext.getOpPackageName()); + mService.setFeature(mToken, userId, feature, enabled, hardwareAuthToken, + mServiceReceiver, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -465,22 +461,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (mService != null) { try { mGetFeatureCallback = callback; - mService.getFeature(userId, feature, mServiceReceiver, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } - - /** - * Pokes the the driver to have it start looking for faces again. - * @hide - */ - @RequiresPermission(MANAGE_BIOMETRIC) - public void userActivity() { - if (mService != null) { - try { - mService.userActivity(); + mService.getFeature(mToken, userId, feature, mServiceReceiver, + mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 8dbaf2115fe5..f4122fe7c625 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -28,8 +28,8 @@ import android.view.Surface; */ interface IFaceService { // Authenticate the given sessionId with a face - void authenticate(IBinder token, long operationId, int userid, - IFaceServiceReceiver receiver, int flags, String opPackageName); + void authenticate(IBinder token, long operationId, int userid, IFaceServiceReceiver receiver, + String opPackageName); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be @@ -51,11 +51,11 @@ interface IFaceService { int callingUid, int callingPid, int callingUserId); // Start face enrollment - void enroll(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver, + void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, String opPackageName, in int [] disabledFeatures, in Surface surface); // Start remote face enrollment - void enrollRemotely(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver, + void enrollRemotely(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, String opPackageName, in int [] disabledFeatures); // Cancel enrollment in progress @@ -80,21 +80,23 @@ interface IFaceService { // Determine if a user has at least one enrolled face boolean hasEnrolledFaces(int userId, String opPackageName); + // Return the LockoutTracker status for the specified user + int getLockoutModeForUser(int userId); + // Gets the authenticator ID for face long getAuthenticatorId(int callingUserId); // Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password) - void resetLockout(int userId, in byte [] token); + void resetLockout(int userId, in byte [] hardwareAuthToken); // Add a callback which gets notified when the face lockout period expired. void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback); - void setFeature(int userId, int feature, boolean enabled, in byte [] token, - IFaceServiceReceiver receiver, String opPackageName); + void setFeature(IBinder token, int userId, int feature, boolean enabled, + in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, String opPackageName); - void getFeature(int userId, int feature, IFaceServiceReceiver receiver, String opPackageName); - - void userActivity(); + void getFeature(IBinder token, int userId, int feature, IFaceServiceReceiver receiver, + String opPackageName); // Give FaceService its ID. See AuthService.java void initializeConfiguration(int sensorId); diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 4787984cdf41..abe63d65102c 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -277,7 +277,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Callback structure provided to {@link FingerprintManager#enroll(byte[], CancellationSignal, - * int, int, EnrollmentCallback)} must provide an implementation of this for listening to + * int, EnrollmentCallback)} must provide an implementation of this for listening to * fingerprint events. * * @hide @@ -387,7 +387,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { - authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId()); + authenticate(crypto, cancel, callback, handler, mContext.getUserId()); } /** @@ -403,18 +403,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, + * Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal, * AuthenticationCallback, Handler, int, Surface)} with {@code surface} set to null. * - * @see FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, + * @see FingerprintManager#authenticate(CryptoObject, CancellationSignal, * AuthenticationCallback, Handler, int, Surface) * * @hide */ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { - authenticate(crypto, cancel, flags, callback, handler, userId, null /* surface */); + @NonNull AuthenticationCallback callback, Handler handler, int userId) { + authenticate(crypto, cancel, callback, handler, userId, null /* surface */); } /** @@ -428,7 +428,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing */ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId, + @NonNull AuthenticationCallback callback, Handler handler, int userId, @Nullable Surface surface) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); @@ -449,7 +449,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing mAuthenticationCallback = callback; mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; - mService.authenticate(mToken, operationId, userId, mServiceReceiver, flags, + mService.authenticate(mToken, operationId, userId, mServiceReceiver, mContext.getOpPackageName(), surface); } catch (RemoteException e) { Slog.w(TAG, "Remote exception while authenticating: ", e); @@ -463,18 +463,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int, int, + * Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int, * EnrollmentCallback, Surface)} with {@code surface} set to null. * - * @see FingerprintManager#enroll(byte[], CancellationSignal, int, int, EnrollmentCallback, + * @see FingerprintManager#enroll(byte[], CancellationSignal, int, EnrollmentCallback, * Surface) * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) - public void enroll(byte [] token, CancellationSignal cancel, int flags, - int userId, EnrollmentCallback callback) { - enroll(token, cancel, flags, userId, callback, null /* surface */); + public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId, + EnrollmentCallback callback) { + enroll(hardwareAuthToken, cancel, userId, callback, null /* surface */); } /** @@ -488,14 +488,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * @param token a unique token provided by a recent creation or verification of device * credentials (e.g. pin, pattern or password). * @param cancel an object that can be used to cancel enrollment - * @param flags optional flags * @param userId the user to whom this fingerprint will belong to * @param callback an object to receive enrollment events * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) - public void enroll(byte [] token, CancellationSignal cancel, int flags, - int userId, EnrollmentCallback callback, @Nullable Surface surface) { + public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId, + EnrollmentCallback callback, @Nullable Surface surface) { if (userId == UserHandle.USER_CURRENT) { userId = getCurrentUserId(); } @@ -515,7 +514,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing if (mService != null) { try { mEnrollmentCallback = callback; - mService.enroll(mToken, token, userId, mServiceReceiver, flags, + mService.enroll(mToken, hardwareAuthToken, userId, mServiceReceiver, mContext.getOpPackageName(), surface); } catch (RemoteException e) { Slog.w(TAG, "Remote exception in enroll: ", e); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 7e251fd24e94..5adba7595ef9 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -33,8 +33,7 @@ interface IFingerprintService { // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes // through FingerprintManager now. void authenticate(IBinder token, long operationId, int userId, - IFingerprintServiceReceiver receiver, int flags, String opPackageName, - in Surface surface); + IFingerprintServiceReceiver receiver, String opPackageName, in Surface surface); // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be @@ -57,8 +56,8 @@ interface IFingerprintService { int callingUid, int callingPid, int callingUserId); // Start fingerprint enrollment - void enroll(IBinder token, in byte [] cryptoToken, int userId, IFingerprintServiceReceiver receiver, - int flags, String opPackageName, in Surface surface); + void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver, + String opPackageName, in Surface surface); // Cancel enrollment in progress void cancelEnrollment(IBinder token); @@ -85,11 +84,14 @@ interface IFingerprintService { // Determine if a user has at least one enrolled fingerprint boolean hasEnrolledFingerprints(int userId, String opPackageName); + // Return the LockoutTracker status for the specified user + int getLockoutModeForUser(int userId); + // Gets the authenticator ID for fingerprint long getAuthenticatorId(int callingUserId); // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password) - void resetLockout(int userId, in byte [] cryptoToken); + void resetLockout(int userId, in byte [] hardwareAuthToken); // Add a callback which gets notified when the fingerprint lockout period expired. void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index b39eaf3f3324..e45cfe27b33f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2047,8 +2047,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mFingerprintCancelSignal.cancel(); } mFingerprintCancelSignal = new CancellationSignal(); - mFpm.authenticate(null, mFingerprintCancelSignal, 0, mFingerprintAuthenticationCallback, - null, userId); + mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal, + mFingerprintAuthenticationCallback, null /* handler */, userId); setFingerprintRunningState(BIOMETRIC_STATE_RUNNING); } } @@ -2065,8 +2065,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mFaceCancelSignal.cancel(); } mFaceCancelSignal = new CancellationSignal(); - mFaceManager.authenticate(null, mFaceCancelSignal, 0, - mFaceAuthenticationCallback, null, userId); + mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal, + mFaceAuthenticationCallback, null /* handler */, userId); setFaceRunningState(BIOMETRIC_STATE_RUNNING); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 9e056cf16ec7..c36bb0472240 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -423,7 +423,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true); mTestableLooper.processAllMessages(); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); verify(mFaceManager).isHardwareDetected(); verify(mFaceManager).hasEnrolledTemplates(anyInt()); } @@ -433,7 +433,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.dispatchStartedWakingUp(); mTestableLooper.processAllMessages(); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -443,7 +443,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.dispatchStartedWakingUp(); mTestableLooper.processAllMessages(); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -455,7 +455,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.dispatchStartedWakingUp(); mTestableLooper.processAllMessages(); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -478,14 +478,14 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.dispatchStartedWakingUp(); mTestableLooper.processAllMessages(); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); // Stop scanning when bouncer becomes visible mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true /* showingBouncer */); mTestableLooper.processAllMessages(); clearInvocations(mFaceManager); mKeyguardUpdateMonitor.requestFaceAuth(); - verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -493,7 +493,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.setKeyguardOccluded(true); mKeyguardUpdateMonitor.setAssistantVisible(true); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -505,7 +505,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -515,7 +515,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -526,7 +526,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -537,7 +537,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT); mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true); - verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt()); + verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt()); } @Test @@ -549,7 +549,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true); mTestableLooper.processAllMessages(); - verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any()); + verify(mFaceManager, never()).authenticate(any(), any(), any(), any()); } @Test diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java index 7a4f70a72252..08a617134221 100644 --- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java +++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java @@ -32,6 +32,9 @@ import android.os.RemoteException; import android.util.Pair; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.biometrics.sensors.LockoutTracker; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -54,6 +57,8 @@ class PreAuthInfo { static final int BIOMETRIC_NOT_ENROLLED = 7; static final int BIOMETRIC_NOT_ENABLED_FOR_APPS = 8; static final int CREDENTIAL_NOT_ENROLLED = 9; + static final int BIOMETRIC_LOCKOUT_TIMED = 10; + static final int BIOMETRIC_LOCKOUT_PERMANENT = 11; @IntDef({AUTHENTICATOR_OK, BIOMETRIC_NO_HARDWARE, BIOMETRIC_DISABLED_BY_DEVICE_POLICY, @@ -62,7 +67,9 @@ class PreAuthInfo { BIOMETRIC_HARDWARE_NOT_DETECTED, BIOMETRIC_NOT_ENROLLED, BIOMETRIC_NOT_ENABLED_FOR_APPS, - CREDENTIAL_NOT_ENROLLED}) + CREDENTIAL_NOT_ENROLLED, + BIOMETRIC_LOCKOUT_TIMED, + BIOMETRIC_LOCKOUT_PERMANENT}) @Retention(RetentionPolicy.SOURCE) @interface AuthenticatorStatus {} @@ -73,7 +80,7 @@ class PreAuthInfo { // Sensors that can be used for this request (e.g. strong enough, enrolled, enabled). final List<BiometricSensor> eligibleSensors; // Sensors that cannot be used for this request. Pair<BiometricSensor, AuthenticatorStatus> - private final List<Pair<BiometricSensor, Integer>> mIneligibleSensors; + final List<Pair<BiometricSensor, Integer>> ineligibleSensors; final boolean credentialAvailable; final boolean confirmationRequested; @@ -156,6 +163,14 @@ class PreAuthInfo { if (!sensor.impl.hasEnrolledTemplates(userId, opPackageName)) { return BIOMETRIC_NOT_ENROLLED; } + + final @LockoutTracker.LockoutMode int lockoutMode = + sensor.impl.getLockoutModeForUser(userId); + if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) { + return BIOMETRIC_LOCKOUT_TIMED; + } else if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) { + return BIOMETRIC_LOCKOUT_PERMANENT; + } } catch (RemoteException e) { return BIOMETRIC_HARDWARE_NOT_DETECTED; } @@ -232,7 +247,7 @@ class PreAuthInfo { this.credentialRequested = credentialRequested; this.eligibleSensors = eligibleSensors; - this.mIneligibleSensors = ineligibleSensors; + this.ineligibleSensors = ineligibleSensors; this.credentialAvailable = credentialAvailable; this.confirmationRequested = confirmationRequested; } @@ -258,9 +273,9 @@ class PreAuthInfo { } } else { // Pick the first sensor error if it exists - if (!mIneligibleSensors.isEmpty()) { - modality |= mIneligibleSensors.get(0).first.modality; - status = mIneligibleSensors.get(0).second; + if (!ineligibleSensors.isEmpty()) { + modality |= ineligibleSensors.get(0).first.modality; + status = ineligibleSensors.get(0).second; } else { modality |= TYPE_CREDENTIAL; status = CREDENTIAL_NOT_ENROLLED; @@ -274,9 +289,9 @@ class PreAuthInfo { } } else { // Pick the first sensor error if it exists - if (!mIneligibleSensors.isEmpty()) { - modality |= mIneligibleSensors.get(0).first.modality; - status = mIneligibleSensors.get(0).second; + if (!ineligibleSensors.isEmpty()) { + modality |= ineligibleSensors.get(0).first.modality; + status = ineligibleSensors.get(0).second; } else { modality |= TYPE_NONE; status = BIOMETRIC_NO_HARDWARE; @@ -293,7 +308,7 @@ class PreAuthInfo { } Slog.d(TAG, "getCanAuthenticateInternal Modality: " + modality - + " AuthenticatorSatus: " + status); + + " AuthenticatorStatus: " + status); return new Pair<>(modality, status); } @@ -325,6 +340,8 @@ class PreAuthInfo { case BIOMETRIC_HARDWARE_NOT_DETECTED: case BIOMETRIC_NOT_ENROLLED: case CREDENTIAL_NOT_ENROLLED: + case BIOMETRIC_LOCKOUT_TIMED: + case BIOMETRIC_LOCKOUT_PERMANENT: break; case BIOMETRIC_DISABLED_BY_DEVICE_POLICY: @@ -379,7 +396,7 @@ class PreAuthInfo { string.append("}"); string.append("\nIneligible:{"); - for (Pair<BiometricSensor, Integer> ineligible : mIneligibleSensors) { + for (Pair<BiometricSensor, Integer> ineligible : ineligibleSensors) { string.append(ineligible.first).append(":").append(ineligible.second).append(" "); } string.append("}"); diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java index 0d4d5893e9b1..6be457474630 100644 --- a/services/core/java/com/android/server/biometrics/Utils.java +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -23,6 +23,8 @@ import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_DISABLED_BY_DE import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_HARDWARE_NOT_DETECTED; import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_INSUFFICIENT_STRENGTH; import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE; +import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_LOCKOUT_PERMANENT; +import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_LOCKOUT_TIMED; import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NOT_ENABLED_FOR_APPS; import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NOT_ENROLLED; import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NO_HARDWARE; @@ -235,6 +237,10 @@ public class Utils { case BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED: biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED; break; + case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT: + case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT: + biometricManagerCode = BiometricManager.BIOMETRIC_SUCCESS; + break; default: Slog.e(BiometricService.TAG, "Unhandled result code: " + biometricConstantsCode); biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE; @@ -289,6 +295,12 @@ public class Utils { case CREDENTIAL_NOT_ENROLLED: return BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL; + case BIOMETRIC_LOCKOUT_TIMED: + return BiometricConstants.BIOMETRIC_ERROR_LOCKOUT; + + case BIOMETRIC_LOCKOUT_PERMANENT: + return BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; + case BIOMETRIC_DISABLED_BY_DEVICE_POLICY: case BIOMETRIC_HARDWARE_NOT_DETECTED: case BIOMETRIC_NOT_ENABLED_FOR_APPS: diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index 92fc33e86a6f..466465e0a3f5 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -32,7 +32,7 @@ import android.util.Slog; * Abstract {@link ClientMonitor} subclass that operations eligible/interested in acquisition * messages should extend. */ -public abstract class AcquisitionClient extends ClientMonitor +public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements ErrorConsumer, Cancellable { private static final String TAG = "Biometrics/AcquisitionClient"; @@ -47,18 +47,28 @@ public abstract class AcquisitionClient extends ClientMonitor private final VibrationEffect mSuccessVibrationEffect; private final VibrationEffect mErrorVibrationEffect; - AcquisitionClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, - boolean restricted, @NonNull String owner, int cookie, int sensorId, int statsModality, + AcquisitionClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction, int statsClient) { - super(finishCallback, context, token, listener, userId, restricted, owner, cookie, sensorId, - statsModality, statsAction, statsClient); + super(context, token, listener, userId, owner, cookie, sensorId, statsModality, statsAction, + statsClient); mPowerManager = context.getSystemService(PowerManager.class); mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); } @Override + public void unableToStart() { + try { + getListener().onError(getSensorId(), getCookie(), + BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send error", e); + } + } + + @Override public void onError(int errorCode, int vendorCode) { logOnError(getContext(), errorCode, vendorCode, getTargetUserId()); try { diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index e4e7715daed1..a9cefbaf8ac0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -22,6 +22,7 @@ import android.app.IActivityTaskManager; import android.app.TaskStackListener; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; @@ -33,7 +34,7 @@ import java.util.ArrayList; /** * A class to keep track of the authentication state for a given client. */ -public abstract class AuthenticationClient extends AcquisitionClient { +public abstract class AuthenticationClient<T> extends AcquisitionClient<T> { private static final String TAG = "Biometrics/AuthenticationClient"; @@ -42,26 +43,29 @@ public abstract class AuthenticationClient extends AcquisitionClient { private final IActivityTaskManager mActivityTaskManager; private final TaskStackListener mTaskStackListener; private final LockoutTracker mLockoutTracker; + private final boolean mIsRestricted; protected final long mOperationId; private long mStartTimeMs; private boolean mAlreadyCancelled; - public AuthenticationClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, - int targetUserId, long operationId, boolean restricted, @NonNull String owner, - int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, - int statsModality, int statsClient, @NonNull TaskStackListener taskStackListener, - @NonNull LockoutTracker lockoutTracker) { - super(finishCallback, context, token, listener, targetUserId, restricted, owner, cookie, - sensorId, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + protected boolean mAuthAttempted; + + public AuthenticationClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, + boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, + int sensorId, boolean isStrongBiometric, int statsModality, int statsClient, + @NonNull TaskStackListener taskStackListener, @NonNull LockoutTracker lockoutTracker) { + super(context, token, listener, targetUserId, owner, cookie, sensorId, + statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); mIsStrongBiometric = isStrongBiometric; mOperationId = operationId; mRequireConfirmation = requireConfirmation; mActivityTaskManager = ActivityTaskManager.getService(); mTaskStackListener = taskStackListener; mLockoutTracker = lockoutTracker; + mIsRestricted = restricted; } public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) { @@ -144,7 +148,7 @@ public abstract class AuthenticationClient extends AcquisitionClient { // Explicitly have if/else here to make it super obvious in case the code is // touched in the future. - if (!getIsRestricted()) { + if (!mIsRestricted) { listener.onAuthenticationSucceeded(getSensorId(), identifier, byteToken, getTargetUserId(), mIsStrongBiometric); } else { @@ -183,7 +187,20 @@ public abstract class AuthenticationClient extends AcquisitionClient { * Start authentication */ @Override - public void start() { + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + + final @LockoutTracker.LockoutMode int lockoutMode = + mLockoutTracker.getLockoutModeForUser(getTargetUserId()); + if (lockoutMode != LockoutTracker.LOCKOUT_NONE) { + Slog.v(TAG, "In lockout mode(" + lockoutMode + ") ; disallowing authentication"); + int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED + ? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT + : BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; + onError(errorCode, 0 /* vendorCode */); + return; + } + try { mActivityTaskManager.registerTaskStackListener(mTaskStackListener); } catch (RemoteException e) { @@ -193,6 +210,7 @@ public abstract class AuthenticationClient extends AcquisitionClient { if (DEBUG) Slog.w(TAG, "Requesting auth for " + getOwnerString()); mStartTimeMs = System.currentTimeMillis(); + mAuthAttempted = true; startHalOperation(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java index 4c24d1a61e45..a784b4b57eea 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java @@ -71,7 +71,7 @@ import java.util.Map; * * @hide */ -public abstract class BiometricServiceBase extends SystemService +public abstract class BiometricServiceBase<T> extends SystemService implements IHwBinder.DeathRecipient { protected static final boolean DEBUG = true; @@ -83,7 +83,6 @@ public abstract class BiometricServiceBase extends SystemService private final String mKeyguardPackage; protected final IActivityTaskManager mActivityTaskManager; private final PowerManager mPowerManager; - private final UserManager mUserManager; protected final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener(); private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable(); @@ -120,7 +119,7 @@ public abstract class BiometricServiceBase extends SystemService if (!hasEnrolledBiometrics(userId)) { Slog.d(getTag(), "Last biometric removed for user: " + userId + ", updating active group"); - updateActiveGroup(userId, null); + updateActiveGroup(userId); } } @@ -128,8 +127,8 @@ public abstract class BiometricServiceBase extends SystemService }; private IBiometricService mBiometricService; - private ClientMonitor mCurrentClient; - private ClientMonitor mPendingClient; + private ClientMonitor<T> mCurrentClient; + private ClientMonitor<T> mPendingClient; private PerformanceTracker mPerformanceTracker; private int mSensorId; protected int mCurrentUserId = UserHandle.USER_NULL; @@ -140,6 +139,11 @@ public abstract class BiometricServiceBase extends SystemService protected abstract String getTag(); /** + * @return a fresh reference to the biometric HAL + */ + protected abstract T getDaemon(); + + /** * @return the biometric utilities for a specific implementation. */ protected abstract BiometricUtils getBiometricUtils(); @@ -153,9 +157,8 @@ public abstract class BiometricServiceBase extends SystemService /** * Notifies the HAL that the user has changed. * @param userId - * @param clientPackage */ - protected abstract void updateActiveGroup(int userId, String clientPackage); + protected abstract void updateActiveGroup(int userId); /** * @param userId @@ -253,7 +256,7 @@ public abstract class BiometricServiceBase extends SystemService FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(), BiometricsProtoEnums.ISSUE_CANCEL_TIMED_OUT); - ClientMonitor newClient = mPendingClient; + ClientMonitor<T> newClient = mPendingClient; mCurrentClient = null; mPendingClient = null; startClient(newClient, false); @@ -339,7 +342,6 @@ public abstract class BiometricServiceBase extends SystemService mAppOps = context.getSystemService(AppOpsManager.class); mActivityTaskManager = ActivityTaskManager.getService(); mPowerManager = mContext.getSystemService(PowerManager.class); - mUserManager = UserManager.get(mContext); mPerformanceTracker = PerformanceTracker.getInstanceForSensorId(getSensorId()); } @@ -456,7 +458,7 @@ public abstract class BiometricServiceBase extends SystemService // When enrollment finishes, update this group's authenticator id, as the HAL has // already generated a new authenticator id when the new biometric is enrolled. if (identifier instanceof Fingerprint) { - updateActiveGroup(((Fingerprint)identifier).getGroupId(), null); + updateActiveGroup(((Fingerprint)identifier).getGroupId()); } } } @@ -520,7 +522,7 @@ public abstract class BiometricServiceBase extends SystemService * Calls from the Manager. These are still on the calling binder's thread. */ - protected void enrollInternal(EnrollClient client, int userId) { + protected void enrollInternal(EnrollClient<T> client, int userId) { if (hasReachedEnrollmentLimit(userId)) { return; } @@ -546,26 +548,26 @@ public abstract class BiometricServiceBase extends SystemService }); } - protected void generateChallengeInternal(GenerateChallengeClient client) { + protected void generateChallengeInternal(GenerateChallengeClient<T> client) { mHandler.post(() -> { startClient(client, true /* initiatedByClient */); }); } - protected void revokeChallengeInternal(RevokeChallengeClient client) { + protected void revokeChallengeInternal(RevokeChallengeClient<T> client) { mHandler.post(() -> { startClient(client, true /* initiatedByClient */); }); } - protected void authenticateInternal(AuthenticationClient client, String opPackageName) { + protected void authenticateInternal(AuthenticationClient<T> client, String opPackageName) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); authenticateInternal(client, opPackageName, callingUid, callingPid, callingUserId); } - protected void authenticateInternal(AuthenticationClient client, + protected void authenticateInternal(AuthenticationClient<T> client, String opPackageName, int callingUid, int callingPid, int callingUserId) { if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid, callingUserId)) { @@ -622,13 +624,13 @@ public abstract class BiometricServiceBase extends SystemService }); } - protected void removeInternal(RemovalClient client) { + protected void removeInternal(RemovalClient<T> client) { mHandler.post(() -> { startClient(client, true /* initiatedByClient */); }); } - protected void cleanupInternal(InternalCleanupClient client) { + protected void cleanupInternal(InternalCleanupClient<T> client) { mHandler.post(() -> { if (DEBUG) { Slog.v(getTag(), "Cleaning up templates for user(" @@ -639,18 +641,9 @@ public abstract class BiometricServiceBase extends SystemService } // Should be done on a handler thread - not on the Binder's thread. - private void startAuthentication(AuthenticationClient client, String opPackageName) { + private void startAuthentication(AuthenticationClient<T> client, String opPackageName) { if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")"); - @LockoutTracker.LockoutMode int lockoutMode = getLockoutMode(client.getTargetUserId()); - if (lockoutMode != LockoutTracker.LOCKOUT_NONE) { - Slog.v(getTag(), "In lockout mode(" + lockoutMode + ") ; disallowing authentication"); - int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED - ? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT - : BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; - client.onError(errorCode, 0 /* vendorCode */); - return; - } startClient(client, true /* initiatedByClient */); } @@ -751,7 +744,7 @@ public abstract class BiometricServiceBase extends SystemService * @param initiatedByClient true for authenticate, remove and enroll */ @VisibleForTesting - void startClient(ClientMonitor newClient, boolean initiatedByClient) { + protected void startClient(ClientMonitor<T> newClient, boolean initiatedByClient) { ClientMonitor currentClient = mCurrentClient; if (currentClient != null) { if (DEBUG) Slog.v(getTag(), "request stop current client " + @@ -811,7 +804,7 @@ public abstract class BiometricServiceBase extends SystemService return; } - if (DEBUG) Slog.v(getTag(), "starting client " + if (DEBUG) Slog.v(getTag(), "Starting client " + mCurrentClient.getClass().getSimpleName() + "(" + mCurrentClient.getOwnerString() + ")" + " targetUserId: " + mCurrentClient.getTargetUserId() @@ -823,7 +816,16 @@ public abstract class BiometricServiceBase extends SystemService return; } - mCurrentClient.start(); + final T daemon = getDaemon(); + if (daemon == null) { + Slog.e(getTag(), "Daemon null, unable to start: " + + mCurrentClient.getClass().getSimpleName()); + mCurrentClient.unableToStart(); + mCurrentClient = null; + return; + } + + mCurrentClient.start(daemon, mClientFinishCallback); notifyClientActiveCallbacks(true); } @@ -855,9 +857,9 @@ public abstract class BiometricServiceBase extends SystemService long t = System.currentTimeMillis(); mAuthenticatorIds.clear(); for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) { - int userId = getUserOrWorkProfileId(null, user.id); + int userId = user.id; if (!mAuthenticatorIds.containsKey(userId)) { - updateActiveGroup(userId, null); + updateActiveGroup(userId); } } @@ -867,17 +869,6 @@ public abstract class BiometricServiceBase extends SystemService } } - /** - * @param clientPackage the package of the caller - * @return the profile id - */ - protected int getUserOrWorkProfileId(String clientPackage, int userId) { - if (!isKeyguard(clientPackage) && isWorkProfile(userId)) { - return userId; - } - return getEffectiveUserId(userId); - } - protected boolean isRestricted() { // Only give privileged apps (like Settings) access to biometric info final boolean restricted = !hasPermission(getManageBiometricPermission()); @@ -920,8 +911,7 @@ public abstract class BiometricServiceBase extends SystemService * @return authenticator id for the calling user */ protected long getAuthenticatorId(int callingUserId) { - final int userId = getUserOrWorkProfileId(null /* clientPackage */, callingUserId); - return mAuthenticatorIds.getOrDefault(userId, 0L); + return mAuthenticatorIds.getOrDefault(callingUserId, 0L); } /** @@ -937,7 +927,7 @@ public abstract class BiometricServiceBase extends SystemService if (getCurrentClient() instanceof InternalCleanupClient) { Slog.w(getTag(), "User switched while performing cleanup"); } - updateActiveGroup(userId, null); + updateActiveGroup(userId); doTemplateCleanupForUser(userId); } @@ -947,41 +937,12 @@ public abstract class BiometricServiceBase extends SystemService } } - /** - * @param userId - * @return true if this is a work profile - */ - private boolean isWorkProfile(int userId) { - UserInfo userInfo = null; - final long token = Binder.clearCallingIdentity(); - try { - userInfo = mUserManager.getUserInfo(userId); - } finally { - Binder.restoreCallingIdentity(token); - } - return userInfo != null && userInfo.isManagedProfile(); - } - - - private int getEffectiveUserId(int userId) { - UserManager um = UserManager.get(mContext); - if (um != null) { - final long callingIdentity = Binder.clearCallingIdentity(); - userId = um.getCredentialOwnerProfile(userId); - Binder.restoreCallingIdentity(callingIdentity); - } else { - Slog.e(getTag(), "Unable to acquire UserManager"); - } - return userId; - } - - private void listenForUserSwitches() { try { ActivityManager.getService().registerUserSwitchObserver( new SynchronousUserSwitchObserver() { @Override - public void onUserSwitching(int newUserId) throws RemoteException { + public void onUserSwitching(int newUserId) { mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */) .sendToTarget(); } @@ -991,8 +952,7 @@ public abstract class BiometricServiceBase extends SystemService } } - private void removeLockoutResetCallback( - LockoutResetMonitor monitor) { + private void removeLockoutResetCallback(LockoutResetMonitor monitor) { mLockoutMonitors.remove(monitor); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java index ea1fde919a5f..5a2d63d667db 100644 --- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java @@ -31,7 +31,7 @@ import java.util.NoSuchElementException; * the current client. Subclasses are responsible for coordinating the interaction with * the biometric's HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.). */ -public abstract class ClientMonitor extends LoggableMonitor implements IBinder.DeathRecipient { +public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinder.DeathRecipient { private static final String TAG = "Biometrics/ClientMonitor"; protected static final boolean DEBUG = BiometricServiceBase.DEBUG; @@ -51,31 +51,26 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D void onClientFinished(ClientMonitor clientMonitor); } - protected final FinishCallback mFinishCallback; - - private final Context mContext; + @NonNull private final Context mContext; private final int mTargetUserId; - // True if client does not have MANAGE_FINGERPRINT permission - private final boolean mIsRestricted; - private final String mOwner; + @NonNull private final String mOwner; private final int mSensorId; // sensorId as configured by the framework - private IBinder mToken; - private ClientMonitorCallbackConverter mListener; + @Nullable private IBinder mToken; + @Nullable private ClientMonitorCallbackConverter mListener; // Currently only used for authentication client. The cookie generated by BiometricService // is never 0. private final int mCookie; boolean mAlreadyDone; + @NonNull protected T mDaemon; + @NonNull protected FinishCallback mFinishCallback; + /** - * @param finishCallback used to notify the ClientMonitor's holder when its lifecycle has - * completed and can be removed from the scheduler * @param context system_server context * @param token a unique token for the client * @param listener recipient of related events (e.g. authentication) * @param userId target user id for operation - * @param restricted whether or not client has the MANAGE_* permission - * permission * @param owner name of the client that owns this * @param cookie BiometricPrompt authentication cookie (to be moved into a subclass soon) * @param sensorId ID of the sensor that the operation should be requested of @@ -83,17 +78,15 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D * @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants * @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants */ - public ClientMonitor(@NonNull FinishCallback finishCallback, @NonNull Context context, - IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId, - boolean restricted, @NonNull String owner, int cookie, int sensorId, int statsModality, - int statsAction, int statsClient) { + public ClientMonitor(@NonNull Context context, @Nullable IBinder token, + @Nullable ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, + int cookie, int sensorId, int statsModality, int statsAction, + int statsClient) { super(statsModality, statsAction, statsClient); - mFinishCallback = finishCallback; mContext = context; mToken = token; mListener = listener; mTargetUserId = userId; - mIsRestricted = restricted; mOwner = owner; mCookie = cookie; mSensorId = sensorId; @@ -112,10 +105,22 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D } /** + * Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null). + * If such a problem is detected, the scheduler will not invoke + * {@link #start(Object, FinishCallback)}. + */ + public abstract void unableToStart(); + + /** * Starts the ClientMonitor's lifecycle. Invokes {@link #startHalOperation()} when internal book * keeping is complete. + * @param daemon reference to the HAL + * @param finishCallback invoked when the operation is complete (succeeds, fails, etc) */ - public abstract void start(); + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + mDaemon = daemon; + mFinishCallback = finishCallback; + } /** * Starts the HAL operation specific to the ClientMonitor subclass. @@ -174,10 +179,6 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D return mListener; } - public final boolean getIsRestricted() { - return mIsRestricted; - } - public final int getTargetUserId() { return mTargetUserId; } diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java index f4863f59db4d..ad14531a9001 100644 --- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java +++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java @@ -126,4 +126,17 @@ public final class ClientMonitorCallbackConverter { mFingerprintServiceReceiver.onChallengeGenerated(challenge); } } + + public void onFeatureSet(boolean success, int feature) throws RemoteException { + if (mFaceServiceReceiver != null) { + mFaceServiceReceiver.onFeatureSet(success, feature); + } + } + + public void onFeatureGet(boolean success, int feature, boolean value) + throws RemoteException { + if (mFaceServiceReceiver != null) { + mFaceServiceReceiver.onFeatureGet(success, feature, value); + } + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java index 4c9f68f89a94..6637ede62b80 100644 --- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java @@ -29,7 +29,7 @@ import java.util.Arrays; /** * A class to keep track of the enrollment state for a given client. */ -public abstract class EnrollClient extends AcquisitionClient { +public abstract class EnrollClient<T> extends AcquisitionClient<T> { private static final String TAG = "Biometrics/EnrollClient"; @@ -41,14 +41,13 @@ public abstract class EnrollClient extends AcquisitionClient { private long mEnrollmentStartTimeMs; private boolean mAlreadyCancelled; - public EnrollClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, - @NonNull byte[] hardwareAuthToken, boolean restricted, String owner, - @NonNull BiometricUtils utils, int timeoutSec, int statsModality, int sensorId, + public EnrollClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils, + int timeoutSec, int statsModality, int sensorId, boolean shouldVibrate) { - super(finishCallback, context, token, listener, userId, restricted, owner, 0 /* cookie */, - sensorId, statsModality, BiometricsProtoEnums.ACTION_ENROLL, - BiometricsProtoEnums.CLIENT_UNKNOWN); + super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, statsModality, + BiometricsProtoEnums.ACTION_ENROLL, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricUtils = utils; mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length); mTimeoutSec = timeoutSec; @@ -88,7 +87,9 @@ public abstract class EnrollClient extends AcquisitionClient { } @Override - public void start() { + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + mEnrollmentStartTimeMs = System.currentTimeMillis(); startHalOperation(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java index 98e83daceb6e..12584cfa7af3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java @@ -16,27 +16,39 @@ package com.android.server.biometrics.sensors; +import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; -public abstract class GenerateChallengeClient extends ClientMonitor { +public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> { private static final String TAG = "GenerateChallengeClient"; protected long mChallenge; - public GenerateChallengeClient(FinishCallback finishCallback, Context context, IBinder token, + public GenerateChallengeClient(Context context, IBinder token, ClientMonitorCallbackConverter listener, String owner, int sensorId) { - super(finishCallback, context, token, listener, 0 /* userId */, false /* restricted */, - owner, 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, - BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); + super(context, token, listener, 0 /* userId */, owner, 0 /* cookie */, sensorId, + BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, + BiometricsProtoEnums.CLIENT_UNKNOWN); } @Override - public void start() { + public void unableToStart() { + try { + getListener().onChallengeGenerated(0L); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send error", e); + } + } + + @Override + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + startHalOperation(); try { getListener().onChallengeGenerated(mChallenge); diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java index e2e96e3f80d1..f3ade65d6748 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java @@ -37,8 +37,8 @@ import java.util.List; * 2) The HAL and Framework are not in sync, and * {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/ */ -public abstract class InternalCleanupClient extends ClientMonitor implements EnumerateConsumer, - RemovalConsumer { +public abstract class InternalCleanupClient<T> extends ClientMonitor<T> + implements EnumerateConsumer, RemovalConsumer { private static final String TAG = "Biometrics/InternalCleanupClient"; @@ -58,17 +58,17 @@ public abstract class InternalCleanupClient extends ClientMonitor implements Enu private final ArrayList<UserTemplate> mUnknownHALTemplates = new ArrayList<>(); private final BiometricUtils mBiometricUtils; private final List<? extends BiometricAuthenticator.Identifier> mEnrolledList; - private ClientMonitor mCurrentTask; + private ClientMonitor<T> mCurrentTask; private final FinishCallback mEnumerateFinishCallback = clientMonitor -> { final List<BiometricAuthenticator.Identifier> unknownHALTemplates = - ((InternalEnumerateClient) mCurrentTask).getUnknownHALTemplates(); + ((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates(); if (!unknownHALTemplates.isEmpty()) { Slog.w(TAG, "Adding " + unknownHALTemplates.size() + " templates for deletion"); } - for (int i = 0; i < unknownHALTemplates.size(); i++) { - mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplates.get(i), + for (BiometricAuthenticator.Identifier unknownHALTemplate : unknownHALTemplates) { + mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplate, mCurrentTask.getTargetUserId())); } @@ -85,22 +85,20 @@ public abstract class InternalCleanupClient extends ClientMonitor implements Enu mFinishCallback.onClientFinished(this); }; - protected abstract InternalEnumerateClient getEnumerateClient(FinishCallback finishCallback, - Context context, IBinder token, int userId, boolean restricted, String owner, + protected abstract InternalEnumerateClient<T> getEnumerateClient(Context context, IBinder token, + int userId, String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils, - int sensorId, int statsModality); + int sensorId); - protected abstract RemovalClient getRemovalClient(FinishCallback finishCallback, - Context context, IBinder token, int biometricId, int userId, boolean restricted, - String owner, BiometricUtils utils, int sensorId, int statsModality); + protected abstract RemovalClient<T> getRemovalClient(Context context, IBinder token, + int biometricId, int userId, String owner, BiometricUtils utils, int sensorId); - protected InternalCleanupClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, int userId, boolean restricted, + protected InternalCleanupClient(@NonNull Context context, int userId, @NonNull String owner, int sensorId, int statsModality, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, @NonNull BiometricUtils utils) { - super(finishCallback, context, null /* token */, null /* ClientMonitorCallbackConverter */, - userId, restricted, owner, 0 /* cookie */, sensorId, statsModality, + super(context, null /* token */, null /* ClientMonitorCallbackConverter */, + userId, owner, 0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricUtils = utils; mEnrolledList = enrolledList; @@ -109,22 +107,28 @@ public abstract class InternalCleanupClient extends ClientMonitor implements Enu private void startCleanupUnknownHalTemplates() { UserTemplate template = mUnknownHALTemplates.get(0); mUnknownHALTemplates.remove(template); - mCurrentTask = getRemovalClient(mRemoveFinishCallback, getContext(), getToken(), - template.mIdentifier.getBiometricId(), template.mUserId, getIsRestricted(), - getContext().getPackageName(), mBiometricUtils, getSensorId(), mStatsModality); + mCurrentTask = getRemovalClient(getContext(), getToken(), + template.mIdentifier.getBiometricId(), template.mUserId, + getContext().getPackageName(), mBiometricUtils, getSensorId()); FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, mStatsModality, BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL); - mCurrentTask.start(); + mCurrentTask.start(mDaemon, mRemoveFinishCallback); } @Override - public void start() { + public void unableToStart() { + // nothing to do here + } + + @Override + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + // Start enumeration. Removal will start if necessary, when enumeration is completed. - mCurrentTask = getEnumerateClient(mEnumerateFinishCallback, getContext(), getToken(), - getTargetUserId(), getIsRestricted(), getOwnerString(), mEnrolledList, - mBiometricUtils, getSensorId(), mStatsModality); - mCurrentTask.start(); + mCurrentTask = getEnumerateClient(getContext(), getToken(), getTargetUserId(), + getOwnerString(), mEnrolledList, mBiometricUtils, getSensorId()); + mCurrentTask.start(daemon, mEnumerateFinishCallback); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java index 6764b2111ad3..9ce271c656c8 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java @@ -31,7 +31,8 @@ import java.util.List; /** * Internal class to help clean up unknown templates in the HAL and Framework */ -public abstract class InternalEnumerateClient extends ClientMonitor implements EnumerateConsumer { +public abstract class InternalEnumerateClient<T> extends ClientMonitor<T> + implements EnumerateConsumer { private static final String TAG = "Biometrics/InternalEnumerateClient"; @@ -42,16 +43,14 @@ public abstract class InternalEnumerateClient extends ClientMonitor implements E // List of templates to remove from the HAL private List<BiometricAuthenticator.Identifier> mUnknownHALTemplates = new ArrayList<>(); - protected InternalEnumerateClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, @NonNull IBinder token, int userId, boolean restricted, + protected InternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId, @NonNull String owner, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, @NonNull BiometricUtils utils, int sensorId, int statsModality) { // Internal enumerate does not need to send results to anyone. Cleanup (enumerate + remove) // is all done internally. - super(finishCallback, context, token, null /* ClientMonitorCallbackConverter */, userId, - restricted, owner, 0 /* cookie */, sensorId, statsModality, - BiometricsProtoEnums.ACTION_ENUMERATE, + super(context, token, null /* ClientMonitorCallbackConverter */, userId, owner, + 0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN); mEnrolledList = enrolledList; mUtils = utils; @@ -68,7 +67,14 @@ public abstract class InternalEnumerateClient extends ClientMonitor implements E } @Override - public void start() { + public void unableToStart() { + // Nothing to do here + } + + @Override + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + // The biometric template ids will be removed when we get confirmation from the HAL startHalOperation(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java index 661f7fcd6c47..b734516322e4 100644 --- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java @@ -27,26 +27,31 @@ import android.util.Slog; /** * A class to keep track of the remove state for a given client. */ -public abstract class RemovalClient extends ClientMonitor implements RemovalConsumer { +public abstract class RemovalClient<T> extends ClientMonitor<T> implements RemovalConsumer { private static final String TAG = "Biometrics/RemovalClient"; protected final int mBiometricId; private final BiometricUtils mBiometricUtils; - public RemovalClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, - int biometricId, int userId, boolean restricted, @NonNull String owner, - @NonNull BiometricUtils utils, int sensorId, int statsModality) { - super(finishCallback, context, token, listener, userId, restricted, owner, 0 /* cookie */, - sensorId, statsModality, BiometricsProtoEnums.ACTION_REMOVE, - BiometricsProtoEnums.CLIENT_UNKNOWN); + public RemovalClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId, + @NonNull String owner, @NonNull BiometricUtils utils, int sensorId, int statsModality) { + super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, statsModality, + BiometricsProtoEnums.ACTION_REMOVE, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricId = biometricId; mBiometricUtils = utils; } @Override - public void start() { + public void unableToStart() { + // Nothing to do here + } + + @Override + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + // The biometric template ids will be removed when we get confirmation from the HAL startHalOperation(); } diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java index 024ff576d230..e00396b054e6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java @@ -16,22 +16,28 @@ package com.android.server.biometrics.sensors; +import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; -public abstract class RevokeChallengeClient extends ClientMonitor { +public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> { - public RevokeChallengeClient(FinishCallback finishCallback, Context context, IBinder token, - String owner, int sensorId) { - super(finishCallback, context, token, null /* listener */, 0 /* userId */, - false /* restricted */, owner, 0 /* cookie */, sensorId, + public RevokeChallengeClient(Context context, IBinder token, String owner, int sensorId) { + super(context, token, null /* listener */, 0 /* userId */, owner, 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); } @Override - public void start() { + public void unableToStart() { + // Nothing to do here + } + + @Override + public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + startHalOperation(); mFinishCallback.onClientFinished(this); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java index 82bef34469fe..a54357e922d2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java @@ -48,11 +48,10 @@ import java.util.ArrayList; * Face-specific authentication client supporting the {@link android.hardware.biometrics.face.V1_0} * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces. */ -class FaceAuthenticationClient extends AuthenticationClient { +class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { private static final String TAG = "FaceAuthenticationClient"; - private final IBiometricsFace mDaemon; private final NotificationManager mNotificationManager; private final UsageStats mUsageStats; @@ -62,23 +61,17 @@ class FaceAuthenticationClient extends AuthenticationClient { private final int[] mKeyguardIgnoreListVendor; private int mLastAcquire; - // We need to track this state since it's possible for applications to request for - // authentication while the device is already locked out. In that case, the client is created - // but not started yet. The user shouldn't receive the error haptics in this case. - private boolean mStarted; - FaceAuthenticationClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, @NonNull IBinder token, + FaceAuthenticationClient(@NonNull Context context, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, int statsClient, @NonNull TaskStackListener taskStackListener, @NonNull LockoutTracker lockoutTracker, @NonNull UsageStats usageStats) { - super(finishCallback, context, token, listener, targetUserId, operationId, restricted, + super(context, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, isStrongBiometric, BiometricsProtoEnums.MODALITY_FACE, statsClient, taskStackListener, lockoutTracker); - mDaemon = daemon; mNotificationManager = context.getSystemService(NotificationManager.class); mUsageStats = usageStats; @@ -94,18 +87,6 @@ class FaceAuthenticationClient extends AuthenticationClient { } @Override - public void start() { - mStarted = true; - super.start(); - } - - @Override - public void cancel() { - mStarted = false; - super.cancel(); - } - - @Override protected void startHalOperation() { try { mDaemon.authenticate(mOperationId); @@ -139,10 +120,6 @@ class FaceAuthenticationClient extends AuthenticationClient { boolean authenticated, ArrayList<Byte> token) { super.onAuthenticated(identifier, authenticated, token); - if (authenticated) { - mStarted = false; - } - mUsageStats.addEvent(new UsageStats.AuthenticationEvent( getStartTimeMs(), System.currentTimeMillis() - getStartTimeMs() /* latency */, @@ -176,7 +153,9 @@ class FaceAuthenticationClient extends AuthenticationClient { } case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT: case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT: - if (mStarted) { + if (mAuthAttempted) { + // Only vibrate if auth was attempted. If the user was already locked out prior + // to starting authentication, do not vibrate. vibrateError(); } break; diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index a39c4b974cdd..33244b8e61a8 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -23,6 +23,7 @@ import android.os.IBinder; import android.os.RemoteException; import com.android.server.biometrics.SensorConfig; +import com.android.server.biometrics.sensors.LockoutTracker; /** * Shim that converts IFaceService into a common reusable IBiometricAuthenticator interface. @@ -68,6 +69,12 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { } @Override + public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) + throws RemoteException { + return mFaceService.getLockoutModeForUser(userId); + } + + @Override public void resetLockout(int userId, byte[] hardwareAuthToken) throws RemoteException { mFaceService.resetLockout(userId, hardwareAuthToken); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java index ee8aa171bdbc..b63b39e3cf6c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java @@ -16,8 +16,11 @@ package com.android.server.biometrics.sensors.face; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricFaceConstants; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.biometrics.face.V1_0.Status; import android.hardware.face.FaceManager; @@ -39,24 +42,22 @@ import java.util.Arrays; * Face-specific enroll client supporting the {@link android.hardware.biometrics.face.V1_0} * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces. */ -public class FaceEnrollClient extends EnrollClient { +public class FaceEnrollClient extends EnrollClient<IBiometricsFace> { private static final String TAG = "FaceEnrollClient"; - private final IBiometricsFace mDaemon; - private final int[] mDisabledFeatures; - private final NativeHandle mSurfaceHandle; - private final int[] mEnrollIgnoreList; - private final int[] mEnrollIgnoreListVendor; + @NonNull private final int[] mDisabledFeatures; + @Nullable private final NativeHandle mSurfaceHandle; + @NonNull private final int[] mEnrollIgnoreList; + @NonNull private final int[] mEnrollIgnoreListVendor; - FaceEnrollClient(FinishCallback finishCallback, Context context, IBiometricsFace daemon, - IBinder token, ClientMonitorCallbackConverter listener, int userId, - byte[] hardwareAuthToken, boolean restricted, String owner, BiometricUtils utils, - int[] disabledFeatures, int timeoutSec, int statsModality, NativeHandle surfaceHandle, + FaceEnrollClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils, + @NonNull int[] disabledFeatures, int timeoutSec, @Nullable NativeHandle surfaceHandle, int sensorId) { - super(finishCallback, context, token, listener, userId, hardwareAuthToken, restricted, - owner, utils, timeoutSec, statsModality, sensorId, false /* shouldVibrate */); - mDaemon = daemon; + super(context, token, listener, userId, hardwareAuthToken, owner, utils, timeoutSec, + BiometricsProtoEnums.MODALITY_FACE, sensorId, false /* shouldVibrate */); mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length); mSurfaceHandle = surfaceHandle; mEnrollIgnoreList = getContext().getResources() diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java index 7d10c59bf828..72188a516d65 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java @@ -31,18 +31,14 @@ import com.android.server.biometrics.sensors.GenerateChallengeClient; * {@link android.hardware.biometrics.face.V1_0} and {@link android.hardware.biometrics.face.V1_1} * HIDL interfaces. */ -public class FaceGenerateChallengeClient extends GenerateChallengeClient { +public class FaceGenerateChallengeClient extends GenerateChallengeClient<IBiometricsFace> { private static final String TAG = "FaceGenerateChallengeClient"; private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes - private final IBiometricsFace mDaemon; - - FaceGenerateChallengeClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, @NonNull IBiometricsFace daemon, @NonNull IBinder token, + FaceGenerateChallengeClient(@NonNull Context context, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) { - super(finishCallback, context, token, listener, owner, sensorId); - mDaemon = daemon; + super(context, token, listener, owner, sensorId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java new file mode 100644 index 000000000000..227d817e31ff --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 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 com.android.server.biometrics.sensors.face; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.V1_0.IBiometricsFace; +import android.hardware.biometrics.face.V1_0.OptionalBool; +import android.hardware.biometrics.face.V1_0.Status; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.ClientMonitor; +import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; + +/** + * Face-specific getFeature client supporting the {@link android.hardware.biometrics.face.V1_0} + * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces. + */ +public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> { + + private static final String TAG = "FaceGetFeatureClient"; + + private final int mFeature; + private final int mFaceId; + + FaceGetFeatureClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, + int sensorId, int feature, int faceId) { + super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, + BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, + BiometricsProtoEnums.CLIENT_UNKNOWN); + mFeature = feature; + mFaceId = faceId; + + } + + @Override + public void unableToStart() { + try { + getListener().onFeatureGet(false /* success */, mFeature, false /* value */); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send error", e); + } + } + + @Override + public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + startHalOperation(); + } + + @Override + protected void startHalOperation() { + try { + final OptionalBool result = mDaemon.getFeature(mFeature, mFaceId); + getListener().onFeatureGet(result.status == Status.OK, mFeature, result.value); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to getFeature", e); + } + mFinishCallback.onClientFinished(this); + } + + @Override + protected void stopHalOperation() { + // Not supported for GetFeature + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java index 2b4c4c8c0fe1..388baa226dee 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java @@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.os.IBinder; @@ -34,36 +35,30 @@ import java.util.List; * {@link android.hardware.biometrics.face.V1_0} and {@link android.hardware.biometrics.face.V1_1} * HIDL interfaces. */ -class FaceInternalCleanupClient extends InternalCleanupClient { - private final IBiometricsFace mDaemon; +class FaceInternalCleanupClient extends InternalCleanupClient<IBiometricsFace> { - FaceInternalCleanupClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, int userId, boolean restricted, String owner, - int sensorId, int statsModality, - @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, + FaceInternalCleanupClient(@NonNull Context context, int userId, @NonNull String owner, + int sensorId, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, @NonNull BiometricUtils utils) { - super(finishCallback, context, userId, restricted, owner, sensorId, statsModality, - enrolledList, utils); - mDaemon = daemon; + super(context, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FACE, enrolledList, + utils); } @Override - protected InternalEnumerateClient getEnumerateClient(FinishCallback finishCallback, - Context context, IBinder token, int userId, boolean restricted, String owner, + protected InternalEnumerateClient<IBiometricsFace> getEnumerateClient(Context context, + IBinder token, int userId, String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList, - BiometricUtils utils, int sensorId, int statsModality) { - return new FaceInternalEnumerateClient(finishCallback, context, mDaemon, token, userId, - restricted, owner, enrolledList, utils, sensorId, statsModality); + BiometricUtils utils, int sensorId) { + return new FaceInternalEnumerateClient(context, token, userId, owner, enrolledList, utils, + sensorId); } @Override - protected RemovalClient getRemovalClient(FinishCallback finishCallback, Context context, - IBinder token, int biometricId, int userId, boolean restricted, String owner, - BiometricUtils utils, int sensorId, int statsModality) { + protected RemovalClient<IBiometricsFace> getRemovalClient(Context context, IBinder token, + int biometricId, int userId, String owner, BiometricUtils utils, int sensorId) { // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove) // is all done internally. - return new FaceRemovalClient(finishCallback, context, mDaemon, token, - null /* ClientMonitorCallbackConverter */, biometricId, userId, restricted, - owner, utils, sensorId, statsModality); + return new FaceRemovalClient(context, token, null /* ClientMonitorCallbackConverter */, + biometricId, userId, owner, utils, sensorId); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java index 1b4597c5f2cd..c6749c5713d9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java @@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.os.IBinder; import android.os.RemoteException; @@ -34,19 +35,15 @@ import java.util.List; * {@link android.hardware.biometrics.face.V1_0} and {@link android.hardware.biometrics.face.V1_1} * HIDL interfaces. */ -class FaceInternalEnumerateClient extends InternalEnumerateClient { +class FaceInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFace> { private static final String TAG = "FaceInternalEnumerateClient"; - private final IBiometricsFace mDaemon; - - FaceInternalEnumerateClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, @NonNull IBinder token, int userId, boolean restricted, + FaceInternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId, @NonNull String owner, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, - @NonNull BiometricUtils utils, int sensorId, int statsModality) { - super(finishCallback, context, token, userId, restricted, owner, enrolledList, utils, - sensorId, statsModality); - mDaemon = daemon; + @NonNull BiometricUtils utils, int sensorId) { + super(context, token, userId, owner, enrolledList, utils, sensorId, + BiometricsProtoEnums.MODALITY_FACE); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java index 2c1939744543..b0ee9810a49b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java @@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.face; import android.annotation.NonNull; import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.os.IBinder; import android.os.RemoteException; @@ -31,18 +32,14 @@ import com.android.server.biometrics.sensors.RemovalClient; * Face-specific removal client supporting the {@link android.hardware.biometrics.face.V1_0} * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces. */ -class FaceRemovalClient extends RemovalClient { +class FaceRemovalClient extends RemovalClient<IBiometricsFace> { private static final String TAG = "FaceRemovalClient"; - private final IBiometricsFace mDaemon; - FaceRemovalClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, @NonNull IBinder token, + FaceRemovalClient(@NonNull Context context, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId, - boolean restricted, @NonNull String owner, @NonNull BiometricUtils utils, int sensorId, - int statsModality) { - super(finishCallback, context, token, listener, biometricId, userId, restricted, owner, - utils, sensorId, statsModality); - mDaemon = daemon; + @NonNull String owner, @NonNull BiometricUtils utils, int sensorId) { + super(context, token, listener, biometricId, userId, owner, utils, sensorId, + BiometricsProtoEnums.MODALITY_FACE); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java new file mode 100644 index 000000000000..441cb14f6600 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 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 com.android.server.biometrics.sensors.face; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.V1_0.IBiometricsFace; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.ClientMonitor; + +import java.util.ArrayList; + +/** + * Face-specific resetLockout client supporting the {@link android.hardware.biometrics.face.V1_0} + * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces. + */ +public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> { + + private static final String TAG = "FaceResetLockoutClient"; + + private final ArrayList<Byte> mHardwareAuthToken; + + FaceResetLockoutClient(@NonNull Context context, int userId, String owner, int sensorId, + byte[] hardwareAuthToken) { + super(context, null /* token */, null /* listener */, userId, owner, 0 /* cookie */, + sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, + BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); + + mHardwareAuthToken = new ArrayList<>(); + for (byte b : hardwareAuthToken) { + mHardwareAuthToken.add(b); + } + } + + @Override + public void unableToStart() { + // Nothing to do here + } + + @Override + public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + + startHalOperation(); + } + + @Override + protected void startHalOperation() { + try { + mDaemon.resetLockout(mHardwareAuthToken); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to reset lockout", e); + } + mFinishCallback.onClientFinished(this); + } + + @Override + protected void stopHalOperation() { + // Not supported for resetLockout + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java index 102efda8a45d..992a678d8205 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java @@ -29,17 +29,13 @@ import com.android.server.biometrics.sensors.RevokeChallengeClient; * Face-specific revokeChallenge client supporting the {@link android.hardware.biometrics.face.V1_0} * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces. */ -public class FaceRevokeChallengeClient extends RevokeChallengeClient { +public class FaceRevokeChallengeClient extends RevokeChallengeClient<IBiometricsFace> { private static final String TAG = "FaceRevokeChallengeClient"; - private final IBiometricsFace mDaemon; - - FaceRevokeChallengeClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, @NonNull IBinder token, @NonNull String owner, - int sensorId) { - super(finishCallback, context, token, owner, sensorId); - mDaemon = daemon; + FaceRevokeChallengeClient(@NonNull Context context, @NonNull IBinder token, + @NonNull String owner, int sensorId) { + super(context, token, owner, sensorId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index 088762c1f39d..050fba28043e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -32,8 +32,6 @@ import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; -import android.hardware.biometrics.face.V1_0.OptionalBool; -import android.hardware.biometrics.face.V1_0.Status; import android.hardware.face.Face; import android.hardware.face.IFaceService; import android.hardware.face.IFaceServiceReceiver; @@ -87,7 +85,7 @@ import java.util.List; * * @hide */ -public class FaceService extends BiometricServiceBase { +public class FaceService extends BiometricServiceBase<IBiometricsFace> { protected static final String TAG = "FaceService"; private static final boolean DEBUG = true; @@ -111,19 +109,12 @@ public class FaceService extends BiometricServiceBase { @Override // Binder call public void generateChallenge(IBinder token, IFaceServiceReceiver receiver, - String opPackageName) throws RemoteException { + String opPackageName) { checkPermission(MANAGE_BIOMETRIC); - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to generateChallenge, daemon null"); - receiver.onChallengeGenerated(0L); - return; - } - - final GenerateChallengeClient client = new FaceGenerateChallengeClient( - mClientFinishCallback, getContext(), daemon, token, - new ClientMonitorCallbackConverter(receiver), opPackageName, getSensorId()); + final GenerateChallengeClient client = new FaceGenerateChallengeClient(getContext(), + token, new ClientMonitorCallbackConverter(receiver), opPackageName, + getSensorId()); generateChallengeInternal(client); } @@ -131,14 +122,8 @@ public class FaceService extends BiometricServiceBase { public void revokeChallenge(IBinder token, String owner) { checkPermission(MANAGE_BIOMETRIC); - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to revokeChallenge, daemon null"); - return; - } - - final RevokeChallengeClient client = new FaceRevokeChallengeClient( - mClientFinishCallback, getContext(), daemon, token, owner, getSensorId()); + final RevokeChallengeClient client = new FaceRevokeChallengeClient(getContext(), token, + owner, getSensorId()); // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks. if (getCurrentClient() == null) { @@ -153,37 +138,27 @@ public class FaceService extends BiometricServiceBase { } @Override // Binder call - public void enroll(int userId, final IBinder token, final byte[] cryptoToken, + public void enroll(int userId, final IBinder token, final byte[] hardwareAuthToken, final IFaceServiceReceiver receiver, final String opPackageName, - final int[] disabledFeatures, Surface surface) throws RemoteException { + final int[] disabledFeatures, Surface surface) { checkPermission(MANAGE_BIOMETRIC); - updateActiveGroup(userId, opPackageName); + updateActiveGroup(userId); mHandler.post(() -> { mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, UserHandle.CURRENT); }); - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to enroll, daemon null"); - receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - return; - } - - final boolean restricted = isRestricted(); - final EnrollClient client = new FaceEnrollClient(mClientFinishCallback, getContext(), - daemon, token, new ClientMonitorCallbackConverter(receiver), - userId, cryptoToken, restricted, opPackageName, getBiometricUtils(), - disabledFeatures, ENROLL_TIMEOUT_SEC, statsModality(), + final EnrollClient client = new FaceEnrollClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken, + opPackageName, getBiometricUtils(), disabledFeatures, ENROLL_TIMEOUT_SEC, convertSurfaceToNativeHandle(surface), getSensorId()); enrollInternal(client, userId); } @Override // Binder call - public void enrollRemotely(int userId, final IBinder token, final byte[] cryptoToken, + public void enrollRemotely(int userId, final IBinder token, final byte[] hardwareAuthToken, final IFaceServiceReceiver receiver, final String opPackageName, final int[] disabledFeatures) { checkPermission(MANAGE_BIOMETRIC); @@ -198,27 +173,18 @@ public class FaceService extends BiometricServiceBase { @Override // Binder call public void authenticate(final IBinder token, final long opId, int userId, - final IFaceServiceReceiver receiver, final int flags, - final String opPackageName) throws RemoteException { + final IFaceServiceReceiver receiver, final String opPackageName) { checkPermission(USE_BIOMETRIC_INTERNAL); - updateActiveGroup(userId, opPackageName); - - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to authenticate, daemon null"); - receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - return; - } + updateActiveGroup(userId); final boolean restricted = isRestricted(); final int statsClient = isKeyguard(opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD : BiometricsProtoEnums.CLIENT_UNKNOWN; - final AuthenticationClient client = new FaceAuthenticationClient(mClientFinishCallback, - getContext(), daemon, token, new ClientMonitorCallbackConverter(receiver), - userId, opId, restricted, opPackageName, 0 /* cookie */, - false /* requireConfirmation */, getSensorId(), isStrongBiometric(), - statsClient, mTaskStackListener, mLockoutTracker, mUsageStats); + final AuthenticationClient client = new FaceAuthenticationClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), userId, opId, restricted, + opPackageName, 0 /* cookie */, false /* requireConfirmation */, getSensorId(), + isStrongBiometric(), statsClient, mTaskStackListener, mLockoutTracker, + mUsageStats); authenticateInternal(client, opPackageName); } @@ -226,23 +192,14 @@ public class FaceService extends BiometricServiceBase { public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long opId, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, int callingUid, int callingPid, - int callingUserId) throws RemoteException { + int callingUserId) { checkPermission(USE_BIOMETRIC_INTERNAL); - updateActiveGroup(userId, opPackageName); - - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to prepare for authentication, daemon null"); - sensorReceiver.onError(getSensorId(), cookie, - BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); - return; - } + updateActiveGroup(userId); final boolean restricted = true; // BiometricPrompt is always restricted - final AuthenticationClient client = new FaceAuthenticationClient(mClientFinishCallback, - getContext(), daemon, token, new ClientMonitorCallbackConverter(sensorReceiver), - userId, opId, restricted, opPackageName, cookie, requireConfirmation, - getSensorId(), isStrongBiometric(), + final AuthenticationClient client = new FaceAuthenticationClient(getContext(), token, + new ClientMonitorCallbackConverter(sensorReceiver), userId, opId, restricted, + opPackageName, cookie, requireConfirmation, getSensorId(), isStrongBiometric(), BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, mTaskStackListener, mLockoutTracker, mUsageStats); authenticateInternal(client, opPackageName, callingUid, callingPid, @@ -272,34 +229,23 @@ public class FaceService extends BiometricServiceBase { @Override // Binder call public void remove(final IBinder token, final int faceId, final int userId, - final IFaceServiceReceiver receiver, final String opPackageName) - throws RemoteException { + final IFaceServiceReceiver receiver, final String opPackageName) { checkPermission(MANAGE_BIOMETRIC); - updateActiveGroup(userId, opPackageName); + updateActiveGroup(userId); if (token == null) { Slog.w(TAG, "remove(): token is null"); return; } - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to remove, daemon null"); - receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - return; - } - - final boolean restricted = isRestricted(); - final RemovalClient client = new FaceRemovalClient(mClientFinishCallback, getContext(), - daemon, token, new ClientMonitorCallbackConverter(receiver), faceId, userId, - restricted, opPackageName, getBiometricUtils(), getSensorId(), statsModality()); + final RemovalClient client = new FaceRemovalClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName, + getBiometricUtils(), getSensorId()); removeInternal(client); } @Override - public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback) - throws RemoteException { + public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback) { checkPermission(USE_BIOMETRIC_INTERNAL); FaceService.super.addLockoutResetCallback(callback); } @@ -369,6 +315,12 @@ public class FaceService extends BiometricServiceBase { return FaceService.this.hasEnrolledBiometrics(userId); } + @Override + public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) { + checkPermission(USE_BIOMETRIC_INTERNAL); + return mLockoutTracker.getLockoutModeForUser(userId); + } + @Override // Binder call public long getAuthenticatorId(int callingUserId) { checkPermission(USE_BIOMETRIC_INTERNAL); @@ -386,65 +338,49 @@ public class FaceService extends BiometricServiceBase { Slog.d(TAG, "Resetting lockout for user: " + userId); - updateActiveGroup(userId, null /* opPackageName */); - try { - final ArrayList<Byte> token = new ArrayList<>(); - for (int i = 0; i < hardwareAuthToken.length; i++) { - token.add(hardwareAuthToken[i]); - } - mDaemon.resetLockout(token); - } catch (RemoteException e) { - Slog.e(getTag(), "Unable to reset lockout", e); - } + updateActiveGroup(userId); + final FaceResetLockoutClient client = new FaceResetLockoutClient(getContext(), + userId, getContext().getOpPackageName(), getSensorId(), hardwareAuthToken); + startClient(client, true /* initiatedByClient */); }); } @Override - public void setFeature(int userId, int feature, boolean enabled, final byte[] token, - IFaceServiceReceiver receiver, final String opPackageName) { + public void setFeature(final IBinder token, int userId, int feature, boolean enabled, + final byte[] hardwareAuthToken, IFaceServiceReceiver receiver, + final String opPackageName) { checkPermission(MANAGE_BIOMETRIC); mHandler.post(() -> { if (DEBUG) { Slog.d(TAG, "setFeature for user(" + userId + ")"); } - updateActiveGroup(userId, opPackageName); + updateActiveGroup(userId); if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) { Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature); return; } - final ArrayList<Byte> byteToken = new ArrayList<>(); - for (int i = 0; i < token.length; i++) { - byteToken.add(token[i]); - } - - // TODO: Support multiple faces final int faceId = getFirstTemplateForUser(mCurrentUserId); - if (mDaemon != null) { - try { - final int result = mDaemon.setFeature(feature, enabled, byteToken, faceId); - receiver.onFeatureSet(result == Status.OK, feature); - } catch (RemoteException e) { - Slog.e(getTag(), "Unable to set feature: " + feature - + " to enabled:" + enabled, e); - } - } + final FaceSetFeatureClient client = new FaceSetFeatureClient(getContext(), + token, new ClientMonitorCallbackConverter(receiver), userId, opPackageName, + getSensorId(), feature, enabled, hardwareAuthToken, faceId); + startClient(client, true /* initiatedByClient */); }); } @Override - public void getFeature(int userId, int feature, IFaceServiceReceiver receiver, - final String opPackageName) { + public void getFeature(final IBinder token, int userId, int feature, + IFaceServiceReceiver receiver, final String opPackageName) { checkPermission(MANAGE_BIOMETRIC); mHandler.post(() -> { if (DEBUG) { Slog.d(TAG, "getFeature for user(" + userId + ")"); } - updateActiveGroup(userId, opPackageName); + updateActiveGroup(userId); // This should ideally return tri-state, but the user isn't shown settings unless // they are enrolled so it's fine for now. if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) { @@ -455,31 +391,14 @@ public class FaceService extends BiometricServiceBase { // TODO: Support multiple faces final int faceId = getFirstTemplateForUser(mCurrentUserId); - if (mDaemon != null) { - try { - OptionalBool result = mDaemon.getFeature(feature, faceId); - receiver.onFeatureGet(result.status == Status.OK, feature, result.value); - } catch (RemoteException e) { - Slog.e(getTag(), "Unable to getRequireAttention", e); - } - } + final FaceGetFeatureClient client = new FaceGetFeatureClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), userId, opPackageName, + getSensorId(), feature, faceId); + startClient(client, true /* initiatedByClient */); }); } - @Override - public void userActivity() { - checkPermission(MANAGE_BIOMETRIC); - - if (mDaemon != null) { - try { - mDaemon.userActivity(); - } catch (RemoteException e) { - Slog.e(getTag(), "Unable to send userActivity", e); - } - } - } - // TODO: Support multiple faces private int getFirstTemplateForUser(int user) { final List<Face> faces = FaceService.this.getEnrolledTemplates(user); @@ -658,6 +577,11 @@ public class FaceService extends BiometricServiceBase { } @Override + protected IBiometricsFace getDaemon() { + return getFaceDaemon(); + } + + @Override protected BiometricUtils getBiometricUtils() { return FaceUtils.getInstance(); } @@ -683,12 +607,11 @@ public class FaceService extends BiometricServiceBase { } @Override - protected void updateActiveGroup(int userId, String clientPackage) { + protected void updateActiveGroup(int userId) { IBiometricsFace daemon = getFaceDaemon(); if (daemon != null) { try { - userId = getUserOrWorkProfileId(clientPackage, userId); if (userId != mCurrentUserId) { final File baseDir = Environment.getDataVendorDeDirectory(userId); final File faceDir = new File(baseDir, FACE_DATA_DIR); @@ -770,19 +693,10 @@ public class FaceService extends BiometricServiceBase { @Override protected void doTemplateCleanupForUser(int userId) { - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "daemon null, skipping template cleanup"); - return; - } - - final boolean restricted = !hasPermission(getManageBiometricPermission()); final List<? extends BiometricAuthenticator.Identifier> enrolledList = getEnrolledTemplates(userId); - final FaceInternalCleanupClient client = new FaceInternalCleanupClient( - mClientFinishCallback, getContext(), daemon, userId, restricted, - getContext().getOpPackageName(), getSensorId(), statsModality(), enrolledList, - getBiometricUtils()); + final FaceInternalCleanupClient client = new FaceInternalCleanupClient(getContext(), userId, + getContext().getOpPackageName(), getSensorId(), enrolledList, getBiometricUtils()); cleanupInternal(client); } @@ -816,7 +730,7 @@ public class FaceService extends BiometricServiceBase { if (DEBUG) Slog.v(TAG, "Face HAL id: " + halId); if (halId != 0) { loadAuthenticatorIds(); - updateActiveGroup(ActivityManager.getCurrentUser(), null); + updateActiveGroup(ActivityManager.getCurrentUser()); doTemplateCleanupForUser(ActivityManager.getCurrentUser()); } else { Slog.w(TAG, "Failed to open Face HAL!"); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java new file mode 100644 index 000000000000..91f63e185ff8 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 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 com.android.server.biometrics.sensors.face; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.V1_0.IBiometricsFace; +import android.hardware.biometrics.face.V1_0.Status; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.ClientMonitor; +import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; + +import java.util.ArrayList; + +/** + * Face-specific setFeature client supporting the {@link android.hardware.biometrics.face.V1_0} + * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces. + */ +public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> { + + private static final String TAG = "FaceSetFeatureClient"; + + private final int mFeature; + private final boolean mEnabled; + private final ArrayList<Byte> mHardwareAuthToken; + private final int mFaceId; + + FaceSetFeatureClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull String owner, int sensorId, int feature, boolean enabled, + byte[] hardwareAuthToken, int faceId) { + super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, + BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, + BiometricsProtoEnums.CLIENT_UNKNOWN); + mFeature = feature; + mEnabled = enabled; + mFaceId = faceId; + + mHardwareAuthToken = new ArrayList<>(); + for (byte b : hardwareAuthToken) { + mHardwareAuthToken.add(b); + } + } + + @Override + public void unableToStart() { + try { + getListener().onFeatureSet(false /* success */, mFeature); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send error", e); + } + } + + @Override + public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + + startHalOperation(); + mFinishCallback.onClientFinished(this); + } + + @Override + protected void startHalOperation() { + try { + final int result = mDaemon.setFeature(mFeature, mEnabled, mHardwareAuthToken, mFaceId); + getListener().onFeatureSet(result == Status.OK, mFeature); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e); + } + } + + @Override + protected void stopHalOperation() { + // Not supported for SetFeature + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java index d4e9882aeef1..ba89d51b1f61 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java @@ -41,26 +41,22 @@ import java.util.ArrayList; * {@link android.hardware.biometrics.fingerprint.V2_1} and * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces. */ -class FingerprintAuthenticationClient extends AuthenticationClient { +class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFingerprint> { private static final String TAG = "Biometrics/FingerprintAuthClient"; - private final IBiometricsFingerprint mDaemon; private final LockoutFrameworkImpl mLockoutFrameworkImpl; - FingerprintAuthenticationClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, @NonNull IBiometricsFingerprint daemon, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, - int targetUserId, long operationId, boolean restricted, @NonNull String owner, - int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric, - @Nullable Surface surface, int statsClient, + FingerprintAuthenticationClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, + boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, + int sensorId, boolean isStrongBiometric, @Nullable Surface surface, int statsClient, @NonNull TaskStackListener taskStackListener, @NonNull LockoutFrameworkImpl lockoutTracker) { - super(finishCallback, context, token, listener, targetUserId, operationId, restricted, + super(context, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, isStrongBiometric, BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, lockoutTracker); - mDaemon = daemon; mLockoutFrameworkImpl = lockoutTracker; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index abfbedaa4489..3418c466aa69 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -23,6 +23,7 @@ import android.os.IBinder; import android.os.RemoteException; import com.android.server.biometrics.SensorConfig; +import com.android.server.biometrics.sensors.LockoutTracker; /** * Shim that converts IFingerprintService into a common reusable IBiometricAuthenticator interface. @@ -68,6 +69,12 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub } @Override + public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) + throws RemoteException { + return mFingerprintService.getLockoutModeForUser(userId); + } + + @Override public void resetLockout(int userId, byte[] hardwareAuthToken) throws RemoteException { mFingerprintService.resetLockout(userId, hardwareAuthToken); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java index e5d2887d3581..34681c38808b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java @@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricFingerprintConstants; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.os.IBinder; import android.os.RemoteException; @@ -33,20 +34,16 @@ import com.android.server.biometrics.sensors.EnrollClient; * {@link android.hardware.biometrics.fingerprint.V2_1} and * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces. */ -public class FingerprintEnrollClient extends EnrollClient { +public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint> { private static final String TAG = "FingerprintEnrollClient"; - private final IBiometricsFingerprint mDaemon; - FingerprintEnrollClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFingerprint daemon, @NonNull IBinder token, + FingerprintEnrollClient(@NonNull Context context, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, - @NonNull byte[] hardwareAuthToken, boolean restricted, @NonNull String owner, - @NonNull BiometricUtils utils, int timeoutSec, int statsModality, - int sensorId, boolean shouldVibrate) { - super(finishCallback, context, token, listener, userId, hardwareAuthToken, restricted, - owner, utils, timeoutSec, statsModality, sensorId, shouldVibrate); - mDaemon = daemon; + @NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils, + int timeoutSec, int sensorId) { + super(context, token, listener, userId, hardwareAuthToken, owner, utils, timeoutSec, + BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId, true /* shouldVibrate */); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java index 5ff49f377f0a..2fa433305070 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java @@ -31,18 +31,14 @@ import com.android.server.biometrics.sensors.GenerateChallengeClient; * {@link android.hardware.biometrics.fingerprint.V2_1} and * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces. */ -public class FingerprintGenerateChallengeClient extends GenerateChallengeClient { +public class FingerprintGenerateChallengeClient + extends GenerateChallengeClient<IBiometricsFingerprint> { private static final String TAG = "FingerprintGenerateChallengeClient"; - private final IBiometricsFingerprint mDaemon; - - FingerprintGenerateChallengeClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, @NonNull IBiometricsFingerprint daemon, - @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, - @NonNull String owner, int sensorId) { - super(finishCallback, context, token, listener, owner, sensorId); - mDaemon = daemon; + FingerprintGenerateChallengeClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) { + super(context, token, listener, owner, sensorId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java index 1688bde935ac..71e76703b9d5 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java @@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.os.IBinder; @@ -34,36 +35,31 @@ import java.util.List; * {@link android.hardware.biometrics.fingerprint.V2_1} and * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces. */ -class FingerprintInternalCleanupClient extends InternalCleanupClient { - private final IBiometricsFingerprint mDaemon; +class FingerprintInternalCleanupClient extends InternalCleanupClient<IBiometricsFingerprint> { - FingerprintInternalCleanupClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, @NonNull IBiometricsFingerprint daemon, int userId, - boolean restricted, @NonNull String owner, int sensorId, int statsModality, - @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, + FingerprintInternalCleanupClient(@NonNull Context context,int userId, @NonNull String owner, + int sensorId, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, @NonNull BiometricUtils utils) { - super(finishCallback, context, userId, restricted, owner, sensorId, statsModality, + super(context, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FINGERPRINT, enrolledList, utils); - mDaemon = daemon; } @Override - protected InternalEnumerateClient getEnumerateClient(FinishCallback finishCallback, - Context context, IBinder token, int userId, boolean restricted, String owner, + protected InternalEnumerateClient<IBiometricsFingerprint> getEnumerateClient( + Context context, IBinder token, int userId, String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils, - int sensorId, int statsModality) { - return new FingerprintInternalEnumerateClient(finishCallback, context, mDaemon, token, - userId, restricted, owner, enrolledList, utils, sensorId, statsModality); + int sensorId) { + return new FingerprintInternalEnumerateClient(context, token, userId, owner, enrolledList, + utils, sensorId); } @Override - protected RemovalClient getRemovalClient(FinishCallback finishCallback, Context context, - IBinder token, int biometricId, int userId, boolean restricted, String owner, - BiometricUtils utils, int sensorId, int statsModality) { + protected RemovalClient<IBiometricsFingerprint> getRemovalClient(Context context, IBinder token, + int biometricId, int userId, String owner, BiometricUtils utils, int sensorId) { // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove) // is all done internally. - return new FingerprintRemovalClient(finishCallback, context, mDaemon, token, - null /* ClientMonitorCallbackConverter */, biometricId, userId, restricted, - owner, utils, sensorId, statsModality); + return new FingerprintRemovalClient(context, token, + null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils, + sensorId); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java index 2b34f087e230..ba412e3956ce 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java @@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint; import android.annotation.NonNull; import android.content.Context; import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.os.IBinder; import android.os.RemoteException; @@ -34,19 +35,15 @@ import java.util.List; * {@link android.hardware.biometrics.fingerprint.V2_1} and * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces. */ -class FingerprintInternalEnumerateClient extends InternalEnumerateClient { +class FingerprintInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFingerprint> { private static final String TAG = "FingerprintInternalEnumerateClient"; - private final IBiometricsFingerprint mDaemon; - - FingerprintInternalEnumerateClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, @NonNull IBiometricsFingerprint daemon, - @NonNull IBinder token, int userId, boolean restricted, @NonNull String owner, + FingerprintInternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId, + @NonNull String owner, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, - @NonNull BiometricUtils utils, int sensorId, int statsModality) { - super(finishCallback, context, token, userId, restricted, owner, enrolledList, utils, - sensorId, statsModality); - mDaemon = daemon; + @NonNull BiometricUtils utils, int sensorId) { + super(context, token, userId, owner, enrolledList, utils, sensorId, + BiometricsProtoEnums.MODALITY_FINGERPRINT); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java index d284dc673ea1..6d7e76162029 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java @@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.fingerprint; import android.annotation.NonNull; import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.os.IBinder; import android.os.RemoteException; @@ -32,19 +33,14 @@ import com.android.server.biometrics.sensors.RemovalClient; * {@link android.hardware.biometrics.fingerprint.V2_1} and * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces. */ -class FingerprintRemovalClient extends RemovalClient { +class FingerprintRemovalClient extends RemovalClient<IBiometricsFingerprint> { private static final String TAG = "FingerprintRemovalClient"; - private final IBiometricsFingerprint mDaemon; - - FingerprintRemovalClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFingerprint daemon, @NonNull IBinder token, + FingerprintRemovalClient(@NonNull Context context, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId, - boolean restricted, @NonNull String owner, @NonNull BiometricUtils utils, int sensorId, - int statsModality) { - super(finishCallback, context, token, listener, biometricId, userId, restricted, owner, - utils, sensorId, statsModality); - mDaemon = daemon; + @NonNull String owner, @NonNull BiometricUtils utils, int sensorId) { + super(context, token, listener, biometricId, userId, owner, utils, sensorId, + BiometricsProtoEnums.MODALITY_FINGERPRINT); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java index 99e9d54b6a5e..ccbea31d7c48 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java @@ -30,17 +30,14 @@ import com.android.server.biometrics.sensors.RevokeChallengeClient; * {@link android.hardware.biometrics.fingerprint.V2_1} and * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces. */ -public class FingerprintRevokeChallengeClient extends RevokeChallengeClient { +public class FingerprintRevokeChallengeClient + extends RevokeChallengeClient<IBiometricsFingerprint> { private static final String TAG = "FingerprintRevokeChallengeClient"; - private final IBiometricsFingerprint mDaemon; - - FingerprintRevokeChallengeClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, @NonNull IBiometricsFingerprint daemon, - @NonNull IBinder token, @NonNull String owner, int sensorId) { - super(finishCallback, context, token, owner, sensorId); - mDaemon = daemon; + FingerprintRevokeChallengeClient(@NonNull Context context, @NonNull IBinder token, + @NonNull String owner, int sensorId) { + super(context, token, owner, sensorId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index ba3d76f3e876..d2a25dba7936 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -91,7 +91,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * * @hide */ -public class FingerprintService extends BiometricServiceBase { +public class FingerprintService extends BiometricServiceBase<IBiometricsFingerprint> { protected static final String TAG = "FingerprintService"; private static final boolean DEBUG = true; @@ -109,19 +109,12 @@ public class FingerprintService extends BiometricServiceBase { @Override // Binder call public void generateChallenge(IBinder token, IFingerprintServiceReceiver receiver, - String opPackageName) throws RemoteException { + String opPackageName) { checkPermission(MANAGE_FINGERPRINT); - final IBiometricsFingerprint daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to generateChallenge, daemon null"); - receiver.onChallengeGenerated(0L); - return; - } - final GenerateChallengeClient client = new FingerprintGenerateChallengeClient( - mClientFinishCallback, getContext(), daemon, token, - new ClientMonitorCallbackConverter(receiver), opPackageName, getSensorId()); + getContext(), token, new ClientMonitorCallbackConverter(receiver), + opPackageName, getSensorId()); generateChallengeInternal(client); } @@ -129,37 +122,21 @@ public class FingerprintService extends BiometricServiceBase { public void revokeChallenge(IBinder token, String owner) { checkPermission(MANAGE_FINGERPRINT); - final IBiometricsFingerprint daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.e(TAG, "startPostEnroll: no fingerprint HAL!"); - return; - } - - final RevokeChallengeClient client = new FingerprintRevokeChallengeClient( - mClientFinishCallback, getContext(), daemon, token, owner, getSensorId()); + final RevokeChallengeClient client = new FingerprintRevokeChallengeClient(getContext(), + token, owner, getSensorId()); revokeChallengeInternal(client); } @Override // Binder call public void enroll(final IBinder token, final byte[] cryptoToken, final int userId, - final IFingerprintServiceReceiver receiver, final int flags, - final String opPackageName, Surface surface) throws RemoteException { + final IFingerprintServiceReceiver receiver, final String opPackageName, + final Surface surface) { checkPermission(MANAGE_FINGERPRINT); - updateActiveGroup(userId, opPackageName); - - final IBiometricsFingerprint daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to enroll, daemon null"); - receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - return; - } + updateActiveGroup(userId); - final boolean restricted = isRestricted(); - final EnrollClient client = new FingerprintEnrollClient(mClientFinishCallback, - getContext(), daemon, token, new ClientMonitorCallbackConverter(receiver), - userId, cryptoToken, restricted, opPackageName, getBiometricUtils(), - ENROLL_TIMEOUT_SEC, statsModality(), getSensorId(), true /* shouldVibrate */); + final EnrollClient client = new FingerprintEnrollClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), userId, cryptoToken, + opPackageName, getBiometricUtils(), ENROLL_TIMEOUT_SEC, getSensorId()); enrollInternal(client, userId); } @@ -172,17 +149,9 @@ public class FingerprintService extends BiometricServiceBase { @Override // Binder call public void authenticate(final IBinder token, final long opId, final int userId, - final IFingerprintServiceReceiver receiver, final int flags, - final String opPackageName, Surface surface) throws RemoteException { - updateActiveGroup(userId, opPackageName); - - final IBiometricsFingerprint daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to authenticate, daemon null"); - receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - return; - } + final IFingerprintServiceReceiver receiver, final String opPackageName, + final Surface surface) { + updateActiveGroup(userId); final boolean isStrongBiometric; final long ident = Binder.clearCallingIdentity(); @@ -195,9 +164,8 @@ public class FingerprintService extends BiometricServiceBase { final boolean restricted = isRestricted(); final int statsClient = isKeyguard(opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD : BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER; - final AuthenticationClient client = new FingerprintAuthenticationClient( - mClientFinishCallback, getContext(), daemon, token, - new ClientMonitorCallbackConverter(receiver), userId, opId, restricted, + final AuthenticationClient client = new FingerprintAuthenticationClient(getContext(), + token, new ClientMonitorCallbackConverter(receiver), userId, opId, restricted, opPackageName, 0 /* cookie */, false /* requireConfirmation */, getSensorId(), isStrongBiometric, surface, statsClient, mTaskStackListener, mLockoutTracker); authenticateInternal(client, opPackageName); @@ -209,21 +177,11 @@ public class FingerprintService extends BiometricServiceBase { int cookie, int callingUid, int callingPid, int callingUserId, Surface surface) throws RemoteException { checkPermission(MANAGE_BIOMETRIC); - updateActiveGroup(userId, opPackageName); - - final IBiometricsFingerprint daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to prepare for authentication, daemon null"); - sensorReceiver.onError(getSensorId(), cookie, - BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - return; - } + updateActiveGroup(userId); final boolean restricted = true; // BiometricPrompt is always restricted - final AuthenticationClient client = new FingerprintAuthenticationClient( - mClientFinishCallback, getContext(), daemon, token, - new ClientMonitorCallbackConverter(sensorReceiver), userId, opId, + final AuthenticationClient client = new FingerprintAuthenticationClient(getContext(), + token, new ClientMonitorCallbackConverter(sensorReceiver), userId, opId, restricted, opPackageName, cookie, false /* requireConfirmation */, getSensorId(), isStrongBiometric(), surface, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, mTaskStackListener, @@ -258,26 +216,16 @@ public class FingerprintService extends BiometricServiceBase { final IFingerprintServiceReceiver receiver, final String opPackageName) throws RemoteException { checkPermission(MANAGE_FINGERPRINT); - updateActiveGroup(userId, opPackageName); + updateActiveGroup(userId); if (token == null) { Slog.w(TAG, "remove(): token is null"); return; } - final IBiometricsFingerprint daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.e(TAG, "Unable to remove, daemon null"); - receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - return; - } - - final boolean restricted = isRestricted(); - final RemovalClient client = new FingerprintRemovalClient(mClientFinishCallback, - getContext(), daemon, token, new ClientMonitorCallbackConverter(receiver), - fingerId, userId, restricted, opPackageName, getBiometricUtils(), - getSensorId(), statsModality()); + final RemovalClient client = new FingerprintRemovalClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), fingerId, userId, opPackageName, + getBiometricUtils(), getSensorId()); removeInternal(client); } @@ -366,6 +314,12 @@ public class FingerprintService extends BiometricServiceBase { } @Override // Binder call + public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) { + checkPermission(USE_BIOMETRIC_INTERNAL); + return mLockoutTracker.getLockoutModeForUser(userId); + } + + @Override // Binder call public long getAuthenticatorId(int callingUserId) { checkPermission(USE_BIOMETRIC_INTERNAL); return FingerprintService.this.getAuthenticatorId(callingUserId); @@ -612,6 +566,11 @@ public class FingerprintService extends BiometricServiceBase { } @Override + protected IBiometricsFingerprint getDaemon() { + return getFingerprintDaemon(); + } + + @Override protected BiometricUtils getBiometricUtils() { return FingerprintUtils.getInstance(); } @@ -635,12 +594,11 @@ public class FingerprintService extends BiometricServiceBase { } @Override - protected void updateActiveGroup(int userId, String clientPackage) { + protected void updateActiveGroup(int userId) { IBiometricsFingerprint daemon = getFingerprintDaemon(); if (daemon != null) { try { - userId = getUserOrWorkProfileId(clientPackage, userId); if (userId != mCurrentUserId) { int firstSdkInt = Build.VERSION.FIRST_SDK_INT; if (firstSdkInt < Build.VERSION_CODES.BASE) { @@ -747,18 +705,10 @@ public class FingerprintService extends BiometricServiceBase { @Override protected void doTemplateCleanupForUser(int userId) { - final IBiometricsFingerprint daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.e(TAG, "daemon null, skipping template cleanup"); - return; - } - - final boolean restricted = !hasPermission(getManageBiometricPermission()); final List<? extends BiometricAuthenticator.Identifier> enrolledList = getEnrolledTemplates(userId); final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient( - mClientFinishCallback, getContext(), daemon, userId, restricted, - getContext().getOpPackageName(), getSensorId(), statsModality(), enrolledList, + getContext(), userId, getContext().getOpPackageName(), getSensorId(), enrolledList, getBiometricUtils()); cleanupInternal(client); } @@ -793,7 +743,7 @@ public class FingerprintService extends BiometricServiceBase { if (halId != 0) { loadAuthenticatorIds(); final int userId = ActivityManager.getCurrentUser(); - updateActiveGroup(userId, null); + updateActiveGroup(userId); doTemplateCleanupForUser(userId); } else { Slog.w(TAG, "Failed to open Fingerprint HAL!"); diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index a2e51371233b..9e0405792746 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -23,6 +23,7 @@ import android.os.IBinder; import android.os.RemoteException; import com.android.server.biometrics.SensorConfig; +import com.android.server.biometrics.sensors.LockoutTracker; /** * TODO(b/141025588): Add JavaDoc. @@ -63,6 +64,12 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { } @Override + public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) + throws RemoteException { + return LockoutTracker.LOCKOUT_NONE; + } + + @Override public void resetLockout(int userId, byte[] hardwareAuthToken) throws RemoteException { } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java index 1e7b606802ea..023ed460429c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java @@ -85,6 +85,11 @@ public class IrisService extends BiometricServiceBase { } @Override + protected Object getDaemon() { + return null; + } + + @Override protected BiometricUtils getBiometricUtils() { return null; } @@ -95,7 +100,7 @@ public class IrisService extends BiometricServiceBase { } @Override - protected void updateActiveGroup(int userId, String clientPackage) { + protected void updateActiveGroup(int userId) { } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index 4afed48ce8ee..f0be9f1d3213 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -64,6 +64,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.internal.statusbar.IStatusBarService; +import com.android.server.biometrics.sensors.LockoutTracker; import org.junit.Before; import org.junit.Test; @@ -825,6 +826,62 @@ public class BiometricServiceTest { } @Test + public void testBiometricAuth_whenBiometricLockoutTimed_sendsErrorAndModality() + throws Exception { + testBiometricAuth_whenLockout(LockoutTracker.LOCKOUT_TIMED, + BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT); + } + + @Test + public void testBiometricAuth_whenBiometricLockoutPermanent_sendsErrorAndModality() + throws Exception { + testBiometricAuth_whenLockout(LockoutTracker.LOCKOUT_PERMANENT, + BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT); + } + + private void testBiometricAuth_whenLockout(@LockoutTracker.LockoutMode int lockoutMode, + int biometricPromptError) throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG); + when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt())) + .thenReturn(lockoutMode); + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, null /* authenticators */); + waitForIdle(); + + // Modality and error are sent + verify(mReceiver1).onError(eq(BiometricAuthenticator.TYPE_FINGERPRINT), + eq(biometricPromptError), eq(0) /* vendorCode */); + } + + @Test + public void testBiometricOrCredentialAuth_whenBiometricLockout_showsCredential() + throws Exception { + when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true); + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG); + when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt())) + .thenReturn(LockoutTracker.LOCKOUT_PERMANENT); + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */, + Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG); + waitForIdle(); + + verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt()); + assertNotNull(mBiometricService.mCurrentAuthSession); + assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL, + mBiometricService.mCurrentAuthSession.getState()); + assertEquals(Authenticators.DEVICE_CREDENTIAL, + mBiometricService.mCurrentAuthSession.mPromptInfo.getAuthenticators()); + verify(mBiometricService.mStatusBarService).showAuthenticationDialog( + eq(mBiometricService.mCurrentAuthSession.mPromptInfo), + any(IBiometricSysuiReceiver.class), + eq(0 /* biometricModality */), + anyBoolean() /* requireConfirmation */, + anyInt() /* userId */, + eq(TEST_PACKAGE_NAME), + anyLong() /* sessionId */); + } + + @Test public void testCombineAuthenticatorBundles_withKeyDeviceCredential_andKeyAuthenticators() { final boolean allowDeviceCredential = false; final @Authenticators.Types int authenticators = @@ -1199,6 +1256,29 @@ public class BiometricServiceTest { } @Test + public void testCanAuthenticate_whenLockoutTimed() throws Exception { + testCanAuthenticate_whenLockedOut(LockoutTracker.LOCKOUT_TIMED); + } + + @Test + public void testCanAuthenticate_whenLockoutPermanent() throws Exception { + testCanAuthenticate_whenLockedOut(LockoutTracker.LOCKOUT_PERMANENT); + } + + private void testCanAuthenticate_whenLockedOut(@LockoutTracker.LockoutMode int lockoutMode) + throws Exception { + // When only biometric is requested, and sensor is strong enough + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG); + + when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt())) + .thenReturn(lockoutMode); + + // Lockout is not considered an error for BiometricManager#canAuthenticate + assertEquals(BiometricManager.BIOMETRIC_SUCCESS, + invokeCanAuthenticate(mBiometricService, Authenticators.BIOMETRIC_STRONG)); + } + + @Test public void testAuthenticatorActualStrength() { // Tuple of OEM config, updatedStrength, and expectedStrength final int[][] testCases = { @@ -1497,6 +1577,8 @@ public class BiometricServiceTest { when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())) .thenReturn(enrolled); when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true); + when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt())) + .thenReturn(LockoutTracker.LOCKOUT_NONE); mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FINGERPRINT, modality, strength, mFingerprintAuthenticator); } @@ -1504,6 +1586,8 @@ public class BiometricServiceTest { if ((modality & BiometricAuthenticator.TYPE_FACE) != 0) { when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(enrolled); when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true); + when(mFaceAuthenticator.getLockoutModeForUser(anyInt())) + .thenReturn(LockoutTracker.LOCKOUT_NONE); mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FACE, modality, strength, mFaceAuthenticator); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java b/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java index 8aa0406469ec..b05a819ba489 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java @@ -225,7 +225,11 @@ public class UtilsTest { {BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE}, {BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT, - BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE} + BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE}, + {BiometricConstants.BIOMETRIC_ERROR_LOCKOUT, + BiometricManager.BIOMETRIC_SUCCESS}, + {BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT, + BiometricManager.BIOMETRIC_SUCCESS} }; for (int i = 0; i < testCases.length; i++) { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java index 8fc9d449ff6e..d4b299db8c4d 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java @@ -51,6 +51,11 @@ public class BiometricServiceBaseTest { } @Override + protected Object getDaemon() { + return null; + } + + @Override protected BiometricUtils getBiometricUtils() { return null; } @@ -61,7 +66,7 @@ public class BiometricServiceBaseTest { } @Override - protected void updateActiveGroup(int userId, String clientPackage) { + protected void updateActiveGroup(int userId) { } @Override |