diff options
| author | 2020-06-29 18:11:00 -0700 | |
|---|---|---|
| committer | 2020-07-01 14:10:53 -0700 | |
| commit | dbe67876999e73a3b42b8b0642091a44d1cfd1a8 (patch) | |
| tree | 1a7be814f415f9b630887f178ac75fcc5e5c0eff | |
| parent | 11e1f825ad0e0dccedbf330b745a93d08a6e57ac (diff) | |
20/n: Update infrastructure to support upcoming scheduler
1) Templates ClientMonitor<T>, so that redundant code can be removed
2) Moves ClientMonitor and subclass's HAL reference and FinishCallback
to be initialized in ClientMonitor#start. This allows the logic
to be centralied in the upcoming scheduler (e.g. HAL availability
check, having the scheduler use an internal FinishCallback, etc)
3) Moved HAL null-checking to a centralized location. As such, also
added abstract ClientMonitor#unableToStart method, which is invoked
when the ClientMonitor can't/shouldn't be started. Each subclass
handles this case individually based on its own API lifecycle
4) Added BiometricAuthenticator interface to query current lockout mode.
Looks like BiometricService was relying on receiving onError(lockout)
being sent before onReadyForAuthentication. However, to clean up the
FingerprintService/FaceService code and move client lifecycle into
ClientMonitor, we shouldn't rely on this ordering.
Note that this change also makes BiometricServiceBase templated solely
for the purpose of getting a reference to the biometric HAL. This is
a little ugly. This is temporary and will only exist during the middle
of the refactor. By the end of the refactor, BiometricServiceBase will
be gone/deleted, and we should end up with a Scheduler<T> :)
Bug: 157790417
Test: Enroll, authenticate, resetLockout, set/getFeature in settings,
internal cleanup (modifying fingerprint/face utils), for
fingerprint and face, and for multi-user/profile
Test: Lockout user, then request authenticate again. Notice no vibration,
no UI, and correct error result
Test: Lockout user, then request auth with biometric|credential.
Credential UI is shown immediately.
Test: Lockout user, then check canAuthenticate. Returns success, since
the hardware is OK, just the user was rejected too many times.
Note that this is functionally the same as before, since the
sensor would have been considered eligible.
Test: atest com.android.server.biometrics
Change-Id: I420002d2b54a4ab530d0698fcc612ee7c770d5ff
41 files changed, 550 insertions, 483 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/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 0cf233790a8d..1be553ee6b99 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -80,6 +80,9 @@ 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); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index b72881ace9df..7111b86daba5 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -84,6 +84,9 @@ 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); 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..4d5060c2c37b 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,11 +47,11 @@ 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, boolean restricted, + @NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction, int statsClient) { - super(finishCallback, context, token, listener, userId, restricted, owner, cookie, sensorId, + super(context, token, listener, userId, restricted, owner, cookie, sensorId, statsModality, statsAction, statsClient); mPowerManager = context.getSystemService(PowerManager.class); mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); @@ -59,6 +59,16 @@ public abstract class AcquisitionClient extends ClientMonitor } @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..3c30623e7308 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"; @@ -48,14 +49,16 @@ public abstract class AuthenticationClient extends AcquisitionClient { private long mStartTimeMs; private boolean mAlreadyCancelled; - public AuthenticationClient(@NonNull FinishCallback finishCallback, @NonNull Context context, + 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(finishCallback, context, token, listener, targetUserId, restricted, owner, cookie, - sensorId, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); + super(context, token, listener, targetUserId, restricted, owner, cookie, sensorId, + statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); mIsStrongBiometric = isStrongBiometric; mOperationId = operationId; mRequireConfirmation = requireConfirmation; @@ -183,7 +186,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 +209,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 f450e03ecdee..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(); @@ -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(); @@ -252,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); @@ -338,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()); } @@ -519,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; } @@ -545,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)) { @@ -621,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(" @@ -638,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 */); } @@ -750,7 +744,7 @@ public abstract class BiometricServiceBase extends SystemService * @param initiatedByClient true for authenticate, remove and enroll */ @VisibleForTesting - protected 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 " + @@ -810,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() @@ -822,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); } @@ -934,21 +937,6 @@ 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 void listenForUserSwitches() { try { ActivityManager.getService().registerUserSwitchObserver( 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 7633a0fd5291..2e75c6c7724c 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,25 +51,24 @@ 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) @@ -83,12 +82,11 @@ 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, - @Nullable 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, boolean restricted, + @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; @@ -112,10 +110,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. 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..7e8af3c62d67 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,12 +41,12 @@ 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, + public EnrollClient(@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, boolean shouldVibrate) { - super(finishCallback, context, token, listener, userId, restricted, owner, 0 /* cookie */, + super(context, token, listener, userId, restricted, owner, 0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENROLL, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricUtils = utils; @@ -88,7 +88,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..b521a87cfee6 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 */, + super(context, token, listener, 0 /* userId */, false /* restricted */, 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..ed63ad05ecce 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,21 +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, boolean restricted, String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils, int sensorId, int statsModality); - 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, boolean restricted, String owner, BiometricUtils utils, + int sensorId, int statsModality); - protected InternalCleanupClient(@NonNull FinishCallback finishCallback, - @NonNull Context context, int userId, boolean restricted, + protected InternalCleanupClient(@NonNull Context context, int userId, boolean restricted, @NonNull String owner, int sensorId, int statsModality, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, @NonNull BiometricUtils utils) { - super(finishCallback, context, null /* token */, null /* ClientMonitorCallbackConverter */, + super(context, null /* token */, null /* ClientMonitorCallbackConverter */, userId, restricted, owner, 0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricUtils = utils; @@ -109,22 +108,29 @@ public abstract class InternalCleanupClient extends ClientMonitor implements Enu private void startCleanupUnknownHalTemplates() { UserTemplate template = mUnknownHALTemplates.get(0); mUnknownHALTemplates.remove(template); - mCurrentTask = getRemovalClient(mRemoveFinishCallback, getContext(), getToken(), + mCurrentTask = getRemovalClient(getContext(), getToken(), template.mIdentifier.getBiometricId(), template.mUserId, getIsRestricted(), getContext().getPackageName(), mBiometricUtils, getSensorId(), mStatsModality); 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(), + getIsRestricted(), getOwnerString(), mEnrolledList, mBiometricUtils, getSensorId(), + mStatsModality); + 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..633cedf4b556 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, - @NonNull String owner, + protected InternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId, + boolean restricted, @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, restricted, 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..68dac6bda40a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java @@ -27,18 +27,18 @@ 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 */, + public RemovalClient(@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(context, token, listener, userId, restricted, owner, 0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_REMOVE, BiometricsProtoEnums.CLIENT_UNKNOWN); mBiometricId = biometricId; @@ -46,7 +46,14 @@ public abstract class RemovalClient extends ClientMonitor implements RemovalCons } @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..f8dff5783ec3 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, - BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, - BiometricsProtoEnums.CLIENT_UNKNOWN); + public RevokeChallengeClient(Context context, IBinder token, String owner, int sensorId) { + super(context, token, null /* listener */, 0 /* userId */, false /* restricted */, 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..ec77880d888f 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,6 +16,8 @@ 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.face.V1_0.IBiometricsFace; @@ -39,24 +41,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, - int sensorId) { - super(finishCallback, context, token, listener, userId, hardwareAuthToken, restricted, + FaceEnrollClient(@NonNull Context context, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull byte[] hardwareAuthToken, boolean restricted, @NonNull String owner, + @NonNull BiometricUtils utils, @NonNull int[] disabledFeatures, int timeoutSec, + int statsModality, @Nullable NativeHandle surfaceHandle, int sensorId) { + super(context, token, listener, userId, hardwareAuthToken, restricted, owner, utils, timeoutSec, statsModality, sensorId, false /* shouldVibrate */); - mDaemon = daemon; 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 index a54e71c72ed6..0b75a68d0e92 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java @@ -33,28 +33,36 @@ 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 { +public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> { private static final String TAG = "FaceGetFeatureClient"; - private final IBiometricsFace mDaemon; private final int mFeature; private final int mFaceId; - FaceGetFeatureClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, @NonNull IBinder token, + FaceGetFeatureClient(@NonNull Context context, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, int feature, int faceId) { - super(finishCallback, context, token, listener, userId, false /* restricted */, owner, + super(context, token, listener, userId, false /* restricted */, owner, 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); - mDaemon = daemon; 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() { + public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); startHalOperation(); } 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..e52f6c7cb747 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 @@ -34,36 +34,32 @@ 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, + FaceInternalCleanupClient(@NonNull Context context, int userId, boolean restricted, + @NonNull String owner, int sensorId, int statsModality, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, @NonNull BiometricUtils utils) { - super(finishCallback, context, userId, restricted, owner, sensorId, statsModality, + super(context, userId, restricted, owner, sensorId, statsModality, enrolledList, utils); - mDaemon = daemon; } @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, boolean restricted, 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); + return new FaceInternalEnumerateClient(context, token, userId, restricted, owner, + enrolledList, utils, sensorId, statsModality); } @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, boolean restricted, String owner, BiometricUtils utils, + int sensorId, int statsModality) { // 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, restricted, owner, utils, sensorId, statsModality); } } 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..83798c56311c 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 @@ -34,19 +34,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, - @NonNull String owner, + FaceInternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId, + boolean restricted, @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, + super(context, token, userId, restricted, owner, enrolledList, utils, sensorId, statsModality); - mDaemon = daemon; } @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..1184ea93f4a3 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 @@ -31,18 +31,15 @@ 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, + super(context, token, listener, biometricId, userId, restricted, owner, utils, sensorId, statsModality); - mDaemon = daemon; } @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 index a54a0176dac1..171ee042f37e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java @@ -31,21 +31,18 @@ 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 { +public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> { private static final String TAG = "FaceResetLockoutClient"; - private final IBiometricsFace mDaemon; private final ArrayList<Byte> mHardwareAuthToken; - FaceResetLockoutClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, int userId, String owner, int sensorId, + FaceResetLockoutClient(@NonNull Context context, int userId, String owner, int sensorId, byte[] hardwareAuthToken) { - super(finishCallback, context, null /* token */, null /* listener */, userId, + super(context, null /* token */, null /* listener */, userId, false /* restricted */, owner, 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); - mDaemon = daemon; mHardwareAuthToken = new ArrayList<>(); for (byte b : hardwareAuthToken) { @@ -54,7 +51,14 @@ public class FaceResetLockoutClient extends ClientMonitor { } @Override - public void start() { + public void unableToStart() { + // Nothing to do here + } + + @Override + public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) { + super.start(daemon, finishCallback); + startHalOperation(); } 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 872c164c932f..aa1db19c4492 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 @@ -85,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; @@ -109,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); } @@ -129,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,7 +140,7 @@ public class FaceService extends BiometricServiceBase { @Override // Binder call public void enroll(int userId, final IBinder token, final byte[] cryptoToken, final IFaceServiceReceiver receiver, final String opPackageName, - final int[] disabledFeatures, Surface surface) throws RemoteException { + final int[] disabledFeatures, Surface surface) { checkPermission(MANAGE_BIOMETRIC); updateActiveGroup(userId); @@ -162,17 +149,9 @@ public class FaceService extends BiometricServiceBase { 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), + final EnrollClient client = new FaceEnrollClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), userId, cryptoToken, restricted, opPackageName, getBiometricUtils(), disabledFeatures, ENROLL_TIMEOUT_SEC, statsModality(), convertSurfaceToNativeHandle(surface), getSensorId()); @@ -197,26 +176,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 String opPackageName) { checkPermission(USE_BIOMETRIC_INTERNAL); updateActiveGroup(userId); - 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; - } - 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); } @@ -224,23 +195,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); - 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; - } - 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, @@ -270,8 +232,7 @@ 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); @@ -280,24 +241,15 @@ public class FaceService extends BiometricServiceBase { 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, + final RemovalClient client = new FaceRemovalClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), faceId, userId, restricted, opPackageName, getBiometricUtils(), getSensorId(), statsModality()); 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); } @@ -367,6 +319,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); @@ -384,16 +342,9 @@ public class FaceService extends BiometricServiceBase { Slog.d(TAG, "Resetting lockout for user: " + userId); - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "daemon null, skipping template cleanup"); - return; - } - updateActiveGroup(userId); - final FaceResetLockoutClient client = new FaceResetLockoutClient( - mClientFinishCallback, getContext(), daemon, userId, - getContext().getOpPackageName(), getSensorId(), hardwareAuthToken); + final FaceResetLockoutClient client = new FaceResetLockoutClient(getContext(), + userId, getContext().getOpPackageName(), getSensorId(), hardwareAuthToken); startClient(client, true /* initiatedByClient */); }); } @@ -416,16 +367,9 @@ public class FaceService extends BiometricServiceBase { final int faceId = getFirstTemplateForUser(mCurrentUserId); - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "daemon null, skipping template cleanup"); - return; - } - - final FaceSetFeatureClient client = new FaceSetFeatureClient(mClientFinishCallback, - getContext(), daemon, token, new ClientMonitorCallbackConverter(receiver), - userId, opPackageName, getSensorId(), feature, enabled, hardwareAuthToken, - faceId); + final FaceSetFeatureClient client = new FaceSetFeatureClient(getContext(), + token, new ClientMonitorCallbackConverter(receiver), userId, opPackageName, + getSensorId(), feature, enabled, hardwareAuthToken, faceId); startClient(client, true /* initiatedByClient */); }); @@ -451,15 +395,9 @@ public class FaceService extends BiometricServiceBase { // TODO: Support multiple faces final int faceId = getFirstTemplateForUser(mCurrentUserId); - final IBiometricsFace daemon = getFaceDaemon(); - if (daemon == null) { - Slog.e(TAG, "daemon null, skipping template cleanup"); - return; - } - - final FaceGetFeatureClient client = new FaceGetFeatureClient(mClientFinishCallback, - getContext(), daemon, token, new ClientMonitorCallbackConverter(receiver), - userId, opPackageName, getSensorId(), feature, faceId); + final FaceGetFeatureClient client = new FaceGetFeatureClient(getContext(), token, + new ClientMonitorCallbackConverter(receiver), userId, opPackageName, + getSensorId(), feature, faceId); startClient(client, true /* initiatedByClient */); }); @@ -643,6 +581,11 @@ public class FaceService extends BiometricServiceBase { } @Override + protected IBiometricsFace getDaemon() { + return getFaceDaemon(); + } + + @Override protected BiometricUtils getBiometricUtils() { return FaceUtils.getInstance(); } @@ -754,19 +697,12 @@ 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, + restricted, getContext().getOpPackageName(), getSensorId(), statsModality(), + enrolledList, getBiometricUtils()); cleanupInternal(client); } 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 index c0420f49b9ed..229608720562 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java @@ -34,25 +34,22 @@ 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 { +public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> { private static final String TAG = "FaceSetFeatureClient"; - private final IBiometricsFace mDaemon; private final int mFeature; private final boolean mEnabled; private final ArrayList<Byte> mHardwareAuthToken; private final int mFaceId; - FaceSetFeatureClient(@NonNull FinishCallback finishCallback, @NonNull Context context, - @NonNull IBiometricsFace daemon, @NonNull IBinder token, + 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(finishCallback, context, token, listener, userId, false /* restricted */, + super(context, token, listener, userId, false /* restricted */, owner, 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); - mDaemon = daemon; mFeature = feature; mEnabled = enabled; mFaceId = faceId; @@ -64,7 +61,18 @@ public class FaceSetFeatureClient extends ClientMonitor { } @Override - public void start() { + 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); } 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..cd593290ec7e 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 @@ -33,20 +33,17 @@ 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, + super(context, token, listener, userId, hardwareAuthToken, restricted, owner, utils, timeoutSec, statsModality, sensorId, shouldVibrate); - mDaemon = daemon; } @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..a2c3e7b65a22 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 @@ -34,35 +34,32 @@ 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, + FingerprintInternalCleanupClient(@NonNull Context context,int userId, boolean restricted, @NonNull String owner, int sensorId, int statsModality, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList, @NonNull BiometricUtils utils) { - super(finishCallback, context, userId, restricted, owner, sensorId, statsModality, + super(context, userId, restricted, owner, sensorId, statsModality, enrolledList, utils); - mDaemon = daemon; } @Override - protected InternalEnumerateClient getEnumerateClient(FinishCallback finishCallback, + protected InternalEnumerateClient<IBiometricsFingerprint> getEnumerateClient( Context context, IBinder token, int userId, boolean restricted, String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils, int sensorId, int statsModality) { - return new FingerprintInternalEnumerateClient(finishCallback, context, mDaemon, token, + return new FingerprintInternalEnumerateClient(context, token, userId, restricted, owner, enrolledList, utils, sensorId, statsModality); } @Override - protected RemovalClient getRemovalClient(FinishCallback finishCallback, Context context, + protected RemovalClient<IBiometricsFingerprint> getRemovalClient(Context context, IBinder token, int biometricId, int userId, boolean restricted, String owner, BiometricUtils utils, int sensorId, int statsModality) { // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove) // is all done internally. - return new FingerprintRemovalClient(finishCallback, context, mDaemon, token, + return new FingerprintRemovalClient(context, token, null /* ClientMonitorCallbackConverter */, biometricId, userId, restricted, owner, utils, sensorId, statsModality); } 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..d03b39ca242d 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 @@ -34,19 +34,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, + boolean restricted, @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, + super(context, token, userId, restricted, owner, enrolledList, utils, sensorId, statsModality); - mDaemon = daemon; } @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..aa7a99666792 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 @@ -32,19 +32,15 @@ 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, + super(context, token, listener, biometricId, userId, restricted, owner, utils, sensorId, statsModality); - mDaemon = daemon; } @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 80c355f47758..e6e5dc2043c4 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 @@ -90,7 +90,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; @@ -108,19 +108,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); } @@ -128,37 +121,23 @@ 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 String opPackageName, Surface surface) { checkPermission(MANAGE_FINGERPRINT); updateActiveGroup(userId); - 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; - } - 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, restricted, + opPackageName, getBiometricUtils(), ENROLL_TIMEOUT_SEC, statsModality(), + getSensorId(), true /* shouldVibrate */); enrollInternal(client, userId); } @@ -172,17 +151,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 { + final String opPackageName, Surface surface) { updateActiveGroup(userId); - 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 boolean isStrongBiometric; final long ident = Binder.clearCallingIdentity(); try { @@ -194,9 +165,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); @@ -210,19 +180,9 @@ public class FingerprintService extends BiometricServiceBase { checkPermission(MANAGE_BIOMETRIC); updateActiveGroup(userId); - 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; - } - 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, @@ -264,19 +224,10 @@ public class FingerprintService extends BiometricServiceBase { 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, restricted, + opPackageName, getBiometricUtils(), getSensorId(), statsModality()); removeInternal(client); } @@ -365,6 +316,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); @@ -513,6 +470,11 @@ public class FingerprintService extends BiometricServiceBase { } @Override + protected IBiometricsFingerprint getDaemon() { + return getFingerprintDaemon(); + } + + @Override protected BiometricUtils getBiometricUtils() { return FingerprintUtils.getInstance(); } @@ -647,19 +609,12 @@ 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, - getBiometricUtils()); + getContext(), userId, restricted, getContext().getOpPackageName(), getSensorId(), + statsModality(), enrolledList, getBiometricUtils()); cleanupInternal(client); } 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 a7c8e7209b06..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; } 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 26268143b3aa..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; } |