Merge changes from topic "clientmonitor-cleanup4"

* changes:
  22/n: Remove "flags" parameter from authenticate and enroll
  21/n: Clean up ClientMonitor parameters
  20/n: Update infrastructure to support upcoming scheduler
  19/n: Remove dead code
  18/n: Make more HAL operations ClientMonitors
This commit is contained in:
Kevin Chyn
2020-07-02 02:57:47 +00:00
committed by Android (Google) Code Review
46 changed files with 915 additions and 687 deletions

View File

@@ -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);

View File

@@ -165,7 +165,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*
* @param crypto object associated with the call or null if none required.
* @param cancel an object that can be used to cancel authentication
* @param flags optional flags; should be 0
* @param callback an object to receive authentication events
* @param handler an optional handler to handle callback events
* @throws IllegalArgumentException if the crypto operation is not supported or is not backed
@@ -177,8 +176,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId());
@NonNull AuthenticationCallback callback, @Nullable Handler handler) {
authenticate(crypto, cancel, callback, handler, mContext.getUserId());
}
/**
@@ -202,7 +201,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*
* @param crypto object associated with the call or null if none required.
* @param cancel an object that can be used to cancel authentication
* @param flags optional flags; should be 0
* @param callback an object to receive authentication events
* @param handler an optional handler to handle callback events
* @param userId userId to authenticate for
@@ -214,8 +212,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler,
int userId) {
@NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -237,7 +234,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate");
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
flags, mContext.getOpPackageName());
mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) {
@@ -260,9 +257,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @see FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback, int[], Surface)
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] token, CancellationSignal cancel,
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures) {
enroll(userId, token, cancel, callback, disabledFeatures, null /* surface */);
enroll(userId, hardwareAuthToken, cancel, callback, disabledFeatures, null /* surface */);
}
/**
@@ -277,7 +274,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @param token a unique token provided by a recent creation or verification of device
* credentials (e.g. pin, pattern or password).
* @param cancel an object that can be used to cancel enrollment
* @param flags optional flags
* @param userId the user to whom this face will belong to
* @param callback an object to receive enrollment events
* @param surface optional camera preview surface for a single-camera device. Must be null if
@@ -285,7 +281,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void enroll(int userId, byte[] token, CancellationSignal cancel,
public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures, @Nullable Surface surface) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
@@ -304,7 +300,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
try {
mEnrollmentCallback = callback;
Trace.beginSection("FaceManager#enroll");
mService.enroll(userId, mToken, token, mServiceReceiver,
mService.enroll(userId, mToken, hardwareAuthToken, mServiceReceiver,
mContext.getOpPackageName(), disabledFeatures, surface);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enroll: ", e);
@@ -329,15 +325,15 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* which point the object is no longer valid. The operation can be canceled by using the
* provided cancel object.
*
* @param token a unique token provided by a recent creation or verification of device
* credentials (e.g. pin, pattern or password).
* @param hardwareAuthToken a unique token provided by a recent creation or verification of
* device credentials (e.g. pin, pattern or password).
* @param cancel an object that can be used to cancel enrollment
* @param userId the user to whom this face will belong to
* @param callback an object to receive enrollment events
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void enrollRemotely(int userId, byte[] token, CancellationSignal cancel,
public void enrollRemotely(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
@@ -356,7 +352,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
try {
mEnrollmentCallback = callback;
Trace.beginSection("FaceManager#enrollRemotely");
mService.enrollRemotely(userId, mToken, token, mServiceReceiver,
mService.enrollRemotely(userId, mToken, hardwareAuthToken, mServiceReceiver,
mContext.getOpPackageName(), disabledFeatures);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enrollRemotely: ", e);
@@ -444,13 +440,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void setFeature(int userId, int feature, boolean enabled, byte[] token,
public void setFeature(int userId, int feature, boolean enabled, byte[] hardwareAuthToken,
SetFeatureCallback callback) {
if (mService != null) {
try {
mSetFeatureCallback = callback;
mService.setFeature(userId, feature, enabled, token, mServiceReceiver,
mContext.getOpPackageName());
mService.setFeature(mToken, userId, feature, enabled, hardwareAuthToken,
mServiceReceiver, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -465,22 +461,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (mService != null) {
try {
mGetFeatureCallback = callback;
mService.getFeature(userId, feature, mServiceReceiver, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
/**
* Pokes the the driver to have it start looking for faces again.
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public void userActivity() {
if (mService != null) {
try {
mService.userActivity();
mService.getFeature(mToken, userId, feature, mServiceReceiver,
mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -28,8 +28,8 @@ import android.view.Surface;
*/
interface IFaceService {
// Authenticate the given sessionId with a face
void authenticate(IBinder token, long operationId, int userid,
IFaceServiceReceiver receiver, int flags, String opPackageName);
void authenticate(IBinder token, long operationId, int userid, IFaceServiceReceiver receiver,
String opPackageName);
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
@@ -51,11 +51,11 @@ interface IFaceService {
int callingUid, int callingPid, int callingUserId);
// Start face enrollment
void enroll(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
String opPackageName, in int [] disabledFeatures, in Surface surface);
// Start remote face enrollment
void enrollRemotely(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
void enrollRemotely(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
String opPackageName, in int [] disabledFeatures);
// Cancel enrollment in progress
@@ -80,21 +80,23 @@ interface IFaceService {
// Determine if a user has at least one enrolled face
boolean hasEnrolledFaces(int userId, String opPackageName);
// Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int userId);
// Gets the authenticator ID for face
long getAuthenticatorId(int callingUserId);
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(int userId, in byte [] token);
void resetLockout(int userId, in byte [] hardwareAuthToken);
// Add a callback which gets notified when the face lockout period expired.
void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback);
void setFeature(int userId, int feature, boolean enabled, in byte [] token,
IFaceServiceReceiver receiver, String opPackageName);
void setFeature(IBinder token, int userId, int feature, boolean enabled,
in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, String opPackageName);
void getFeature(int userId, int feature, IFaceServiceReceiver receiver, String opPackageName);
void userActivity();
void getFeature(IBinder token, int userId, int feature, IFaceServiceReceiver receiver,
String opPackageName);
// Give FaceService its ID. See AuthService.java
void initializeConfiguration(int sensorId);

View File

@@ -277,7 +277,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
/**
* Callback structure provided to {@link FingerprintManager#enroll(byte[], CancellationSignal,
* int, int, EnrollmentCallback)} must provide an implementation of this for listening to
* int, EnrollmentCallback)} must provide an implementation of this for listening to
* fingerprint events.
*
* @hide
@@ -387,7 +387,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId());
authenticate(crypto, cancel, callback, handler, mContext.getUserId());
}
/**
@@ -403,18 +403,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
/**
* Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
* Defaults to {@link FingerprintManager#authenticate(CryptoObject, CancellationSignal,
* AuthenticationCallback, Handler, int, Surface)} with {@code surface} set to null.
*
* @see FingerprintManager#authenticate(CryptoObject, CancellationSignal, int,
* @see FingerprintManager#authenticate(CryptoObject, CancellationSignal,
* AuthenticationCallback, Handler, int, Surface)
*
* @hide
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {
authenticate(crypto, cancel, flags, callback, handler, userId, null /* surface */);
@NonNull AuthenticationCallback callback, Handler handler, int userId) {
authenticate(crypto, cancel, callback, handler, userId, null /* surface */);
}
/**
@@ -428,7 +428,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId,
@NonNull AuthenticationCallback callback, Handler handler, int userId,
@Nullable Surface surface) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
@@ -449,7 +449,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mAuthenticationCallback = callback;
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
mService.authenticate(mToken, operationId, userId, mServiceReceiver, flags,
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
mContext.getOpPackageName(), surface);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
@@ -463,18 +463,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
/**
* Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int, int,
* Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int,
* EnrollmentCallback, Surface)} with {@code surface} set to null.
*
* @see FingerprintManager#enroll(byte[], CancellationSignal, int, int, EnrollmentCallback,
* @see FingerprintManager#enroll(byte[], CancellationSignal, int, EnrollmentCallback,
* Surface)
*
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] token, CancellationSignal cancel, int flags,
int userId, EnrollmentCallback callback) {
enroll(token, cancel, flags, userId, callback, null /* surface */);
public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
EnrollmentCallback callback) {
enroll(hardwareAuthToken, cancel, userId, callback, null /* surface */);
}
/**
@@ -488,14 +488,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @param token a unique token provided by a recent creation or verification of device
* credentials (e.g. pin, pattern or password).
* @param cancel an object that can be used to cancel enrollment
* @param flags optional flags
* @param userId the user to whom this fingerprint will belong to
* @param callback an object to receive enrollment events
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] token, CancellationSignal cancel, int flags,
int userId, EnrollmentCallback callback, @Nullable Surface surface) {
public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
EnrollmentCallback callback, @Nullable Surface surface) {
if (userId == UserHandle.USER_CURRENT) {
userId = getCurrentUserId();
}
@@ -515,7 +514,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
if (mService != null) {
try {
mEnrollmentCallback = callback;
mService.enroll(mToken, token, userId, mServiceReceiver, flags,
mService.enroll(mToken, hardwareAuthToken, userId, mServiceReceiver,
mContext.getOpPackageName(), surface);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enroll: ", e);

View File

@@ -33,8 +33,7 @@ interface IFingerprintService {
// USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
// through FingerprintManager now.
void authenticate(IBinder token, long operationId, int userId,
IFingerprintServiceReceiver receiver, int flags, String opPackageName,
in Surface surface);
IFingerprintServiceReceiver receiver, String opPackageName, in Surface surface);
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
@@ -57,8 +56,8 @@ interface IFingerprintService {
int callingUid, int callingPid, int callingUserId);
// Start fingerprint enrollment
void enroll(IBinder token, in byte [] cryptoToken, int userId, IFingerprintServiceReceiver receiver,
int flags, String opPackageName, in Surface surface);
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
String opPackageName, in Surface surface);
// Cancel enrollment in progress
void cancelEnrollment(IBinder token);
@@ -85,11 +84,14 @@ interface IFingerprintService {
// Determine if a user has at least one enrolled fingerprint
boolean hasEnrolledFingerprints(int userId, String opPackageName);
// Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int userId);
// Gets the authenticator ID for fingerprint
long getAuthenticatorId(int callingUserId);
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(int userId, in byte [] cryptoToken);
void resetLockout(int userId, in byte [] hardwareAuthToken);
// Add a callback which gets notified when the fingerprint lockout period expired.
void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback);

View File

@@ -2047,8 +2047,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mFingerprintCancelSignal.cancel();
}
mFingerprintCancelSignal = new CancellationSignal();
mFpm.authenticate(null, mFingerprintCancelSignal, 0, mFingerprintAuthenticationCallback,
null, userId);
mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal,
mFingerprintAuthenticationCallback, null /* handler */, userId);
setFingerprintRunningState(BIOMETRIC_STATE_RUNNING);
}
}
@@ -2065,8 +2065,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mFaceCancelSignal.cancel();
}
mFaceCancelSignal = new CancellationSignal();
mFaceManager.authenticate(null, mFaceCancelSignal, 0,
mFaceAuthenticationCallback, null, userId);
mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
mFaceAuthenticationCallback, null /* handler */, userId);
setFaceRunningState(BIOMETRIC_STATE_RUNNING);
}
}

View File

@@ -423,7 +423,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
mTestableLooper.processAllMessages();
verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
verify(mFaceManager).isHardwareDetected();
verify(mFaceManager).hasEnrolledTemplates(anyInt());
}
@@ -433,7 +433,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -443,7 +443,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -455,7 +455,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -478,14 +478,14 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
// Stop scanning when bouncer becomes visible
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true /* showingBouncer */);
mTestableLooper.processAllMessages();
clearInvocations(mFaceManager);
mKeyguardUpdateMonitor.requestFaceAuth();
verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -493,7 +493,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.setKeyguardOccluded(true);
mKeyguardUpdateMonitor.setAssistantVisible(true);
verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -505,7 +505,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -515,7 +515,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -526,7 +526,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -537,7 +537,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
}
@Test
@@ -549,7 +549,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
mTestableLooper.processAllMessages();
verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any());
verify(mFaceManager, never()).authenticate(any(), any(), any(), any());
}
@Test

View File

@@ -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("}");

View File

@@ -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:

View File

@@ -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,17 +47,27 @@ public abstract class AcquisitionClient extends ClientMonitor
private final VibrationEffect mSuccessVibrationEffect;
private final VibrationEffect mErrorVibrationEffect;
AcquisitionClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
boolean restricted, @NonNull String owner, int cookie, int sensorId, int statsModality,
AcquisitionClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality,
int statsAction, int statsClient) {
super(finishCallback, context, token, listener, userId, restricted, owner, cookie, sensorId,
statsModality, statsAction, statsClient);
super(context, token, listener, userId, owner, cookie, sensorId, statsModality, statsAction,
statsClient);
mPowerManager = context.getSystemService(PowerManager.class);
mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
}
@Override
public void unableToStart() {
try {
getListener().onError(getSensorId(), getCookie(),
BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send error", e);
}
}
@Override
public void onError(int errorCode, int vendorCode) {
logOnError(getContext(), errorCode, vendorCode, getTargetUserId());

View File

@@ -22,6 +22,7 @@ import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
@@ -33,7 +34,7 @@ import java.util.ArrayList;
/**
* A class to keep track of the authentication state for a given client.
*/
public abstract class AuthenticationClient extends AcquisitionClient {
public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
private static final String TAG = "Biometrics/AuthenticationClient";
@@ -42,26 +43,29 @@ public abstract class AuthenticationClient extends AcquisitionClient {
private final IActivityTaskManager mActivityTaskManager;
private final TaskStackListener mTaskStackListener;
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
protected final long mOperationId;
private long mStartTimeMs;
private boolean mAlreadyCancelled;
public AuthenticationClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
int targetUserId, long operationId, boolean restricted, @NonNull String owner,
int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
int statsModality, int statsClient, @NonNull TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker) {
super(finishCallback, context, token, listener, targetUserId, restricted, owner, cookie,
sensorId, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
protected boolean mAuthAttempted;
public AuthenticationClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
int sensorId, boolean isStrongBiometric, int statsModality, int statsClient,
@NonNull TaskStackListener taskStackListener, @NonNull LockoutTracker lockoutTracker) {
super(context, token, listener, targetUserId, owner, cookie, sensorId,
statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
mRequireConfirmation = requireConfirmation;
mActivityTaskManager = ActivityTaskManager.getService();
mTaskStackListener = taskStackListener;
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
}
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -144,7 +148,7 @@ public abstract class AuthenticationClient extends AcquisitionClient {
// Explicitly have if/else here to make it super obvious in case the code is
// touched in the future.
if (!getIsRestricted()) {
if (!mIsRestricted) {
listener.onAuthenticationSucceeded(getSensorId(), identifier, byteToken,
getTargetUserId(), mIsStrongBiometric);
} else {
@@ -183,7 +187,20 @@ public abstract class AuthenticationClient extends AcquisitionClient {
* Start authentication
*/
@Override
public void start() {
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutTracker.getLockoutModeForUser(getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
Slog.v(TAG, "In lockout mode(" + lockoutMode + ") ; disallowing authentication");
int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED
? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
: BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
onError(errorCode, 0 /* vendorCode */);
return;
}
try {
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
@@ -193,6 +210,7 @@ public abstract class AuthenticationClient extends AcquisitionClient {
if (DEBUG) Slog.w(TAG, "Requesting auth for " + getOwnerString());
mStartTimeMs = System.currentTimeMillis();
mAuthAttempted = true;
startHalOperation();
}

View File

@@ -71,7 +71,7 @@ import java.util.Map;
*
* @hide
*/
public abstract class BiometricServiceBase extends SystemService
public abstract class BiometricServiceBase<T> extends SystemService
implements IHwBinder.DeathRecipient {
protected static final boolean DEBUG = true;
@@ -83,7 +83,6 @@ public abstract class BiometricServiceBase extends SystemService
private final String mKeyguardPackage;
protected final IActivityTaskManager mActivityTaskManager;
private final PowerManager mPowerManager;
private final UserManager mUserManager;
protected final BiometricTaskStackListener mTaskStackListener =
new BiometricTaskStackListener();
private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
@@ -120,7 +119,7 @@ public abstract class BiometricServiceBase extends SystemService
if (!hasEnrolledBiometrics(userId)) {
Slog.d(getTag(), "Last biometric removed for user: " + userId
+ ", updating active group");
updateActiveGroup(userId, null);
updateActiveGroup(userId);
}
}
@@ -128,8 +127,8 @@ public abstract class BiometricServiceBase extends SystemService
};
private IBiometricService mBiometricService;
private ClientMonitor mCurrentClient;
private ClientMonitor mPendingClient;
private ClientMonitor<T> mCurrentClient;
private ClientMonitor<T> mPendingClient;
private PerformanceTracker mPerformanceTracker;
private int mSensorId;
protected int mCurrentUserId = UserHandle.USER_NULL;
@@ -139,6 +138,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.
*/
@@ -153,9 +157,8 @@ public abstract class BiometricServiceBase extends SystemService
/**
* Notifies the HAL that the user has changed.
* @param userId
* @param clientPackage
*/
protected abstract void updateActiveGroup(int userId, String clientPackage);
protected abstract void updateActiveGroup(int userId);
/**
* @param userId
@@ -253,7 +256,7 @@ public abstract class BiometricServiceBase extends SystemService
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
statsModality(), BiometricsProtoEnums.ISSUE_CANCEL_TIMED_OUT);
ClientMonitor newClient = mPendingClient;
ClientMonitor<T> newClient = mPendingClient;
mCurrentClient = null;
mPendingClient = null;
startClient(newClient, false);
@@ -339,7 +342,6 @@ public abstract class BiometricServiceBase extends SystemService
mAppOps = context.getSystemService(AppOpsManager.class);
mActivityTaskManager = ActivityTaskManager.getService();
mPowerManager = mContext.getSystemService(PowerManager.class);
mUserManager = UserManager.get(mContext);
mPerformanceTracker = PerformanceTracker.getInstanceForSensorId(getSensorId());
}
@@ -456,7 +458,7 @@ public abstract class BiometricServiceBase extends SystemService
// When enrollment finishes, update this group's authenticator id, as the HAL has
// already generated a new authenticator id when the new biometric is enrolled.
if (identifier instanceof Fingerprint) {
updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
updateActiveGroup(((Fingerprint)identifier).getGroupId());
}
}
}
@@ -520,7 +522,7 @@ public abstract class BiometricServiceBase extends SystemService
* Calls from the Manager. These are still on the calling binder's thread.
*/
protected void enrollInternal(EnrollClient client, int userId) {
protected void enrollInternal(EnrollClient<T> client, int userId) {
if (hasReachedEnrollmentLimit(userId)) {
return;
}
@@ -546,26 +548,26 @@ public abstract class BiometricServiceBase extends SystemService
});
}
protected void generateChallengeInternal(GenerateChallengeClient client) {
protected void generateChallengeInternal(GenerateChallengeClient<T> client) {
mHandler.post(() -> {
startClient(client, true /* initiatedByClient */);
});
}
protected void revokeChallengeInternal(RevokeChallengeClient client) {
protected void revokeChallengeInternal(RevokeChallengeClient<T> client) {
mHandler.post(() -> {
startClient(client, true /* initiatedByClient */);
});
}
protected void authenticateInternal(AuthenticationClient client, String opPackageName) {
protected void authenticateInternal(AuthenticationClient<T> client, String opPackageName) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
authenticateInternal(client, opPackageName, callingUid, callingPid, callingUserId);
}
protected void authenticateInternal(AuthenticationClient client,
protected void authenticateInternal(AuthenticationClient<T> client,
String opPackageName, int callingUid, int callingPid, int callingUserId) {
if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
callingUserId)) {
@@ -622,13 +624,13 @@ public abstract class BiometricServiceBase extends SystemService
});
}
protected void removeInternal(RemovalClient client) {
protected void removeInternal(RemovalClient<T> client) {
mHandler.post(() -> {
startClient(client, true /* initiatedByClient */);
});
}
protected void cleanupInternal(InternalCleanupClient client) {
protected void cleanupInternal(InternalCleanupClient<T> client) {
mHandler.post(() -> {
if (DEBUG) {
Slog.v(getTag(), "Cleaning up templates for user("
@@ -639,18 +641,9 @@ public abstract class BiometricServiceBase extends SystemService
}
// Should be done on a handler thread - not on the Binder's thread.
private void startAuthentication(AuthenticationClient client, String opPackageName) {
private void startAuthentication(AuthenticationClient<T> client, String opPackageName) {
if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
@LockoutTracker.LockoutMode int lockoutMode = getLockoutMode(client.getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
Slog.v(getTag(), "In lockout mode(" + lockoutMode + ") ; disallowing authentication");
int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED
? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
: BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
client.onError(errorCode, 0 /* vendorCode */);
return;
}
startClient(client, true /* initiatedByClient */);
}
@@ -751,7 +744,7 @@ public abstract class BiometricServiceBase extends SystemService
* @param initiatedByClient true for authenticate, remove and enroll
*/
@VisibleForTesting
void startClient(ClientMonitor newClient, boolean initiatedByClient) {
protected void startClient(ClientMonitor<T> newClient, boolean initiatedByClient) {
ClientMonitor currentClient = mCurrentClient;
if (currentClient != null) {
if (DEBUG) Slog.v(getTag(), "request stop current client " +
@@ -811,7 +804,7 @@ public abstract class BiometricServiceBase extends SystemService
return;
}
if (DEBUG) Slog.v(getTag(), "starting client "
if (DEBUG) Slog.v(getTag(), "Starting client "
+ mCurrentClient.getClass().getSimpleName()
+ "(" + mCurrentClient.getOwnerString() + ")"
+ " targetUserId: " + mCurrentClient.getTargetUserId()
@@ -823,7 +816,16 @@ public abstract class BiometricServiceBase extends SystemService
return;
}
mCurrentClient.start();
final T daemon = getDaemon();
if (daemon == null) {
Slog.e(getTag(), "Daemon null, unable to start: "
+ mCurrentClient.getClass().getSimpleName());
mCurrentClient.unableToStart();
mCurrentClient = null;
return;
}
mCurrentClient.start(daemon, mClientFinishCallback);
notifyClientActiveCallbacks(true);
}
@@ -855,9 +857,9 @@ public abstract class BiometricServiceBase extends SystemService
long t = System.currentTimeMillis();
mAuthenticatorIds.clear();
for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
int userId = getUserOrWorkProfileId(null, user.id);
int userId = user.id;
if (!mAuthenticatorIds.containsKey(userId)) {
updateActiveGroup(userId, null);
updateActiveGroup(userId);
}
}
@@ -867,17 +869,6 @@ public abstract class BiometricServiceBase extends SystemService
}
}
/**
* @param clientPackage the package of the caller
* @return the profile id
*/
protected int getUserOrWorkProfileId(String clientPackage, int userId) {
if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
return userId;
}
return getEffectiveUserId(userId);
}
protected boolean isRestricted() {
// Only give privileged apps (like Settings) access to biometric info
final boolean restricted = !hasPermission(getManageBiometricPermission());
@@ -920,8 +911,7 @@ public abstract class BiometricServiceBase extends SystemService
* @return authenticator id for the calling user
*/
protected long getAuthenticatorId(int callingUserId) {
final int userId = getUserOrWorkProfileId(null /* clientPackage */, callingUserId);
return mAuthenticatorIds.getOrDefault(userId, 0L);
return mAuthenticatorIds.getOrDefault(callingUserId, 0L);
}
/**
@@ -937,7 +927,7 @@ public abstract class BiometricServiceBase extends SystemService
if (getCurrentClient() instanceof InternalCleanupClient) {
Slog.w(getTag(), "User switched while performing cleanup");
}
updateActiveGroup(userId, null);
updateActiveGroup(userId);
doTemplateCleanupForUser(userId);
}
@@ -947,41 +937,12 @@ public abstract class BiometricServiceBase extends SystemService
}
}
/**
* @param userId
* @return true if this is a work profile
*/
private boolean isWorkProfile(int userId) {
UserInfo userInfo = null;
final long token = Binder.clearCallingIdentity();
try {
userInfo = mUserManager.getUserInfo(userId);
} finally {
Binder.restoreCallingIdentity(token);
}
return userInfo != null && userInfo.isManagedProfile();
}
private int getEffectiveUserId(int userId) {
UserManager um = UserManager.get(mContext);
if (um != null) {
final long callingIdentity = Binder.clearCallingIdentity();
userId = um.getCredentialOwnerProfile(userId);
Binder.restoreCallingIdentity(callingIdentity);
} else {
Slog.e(getTag(), "Unable to acquire UserManager");
}
return userId;
}
private void listenForUserSwitches() {
try {
ActivityManager.getService().registerUserSwitchObserver(
new SynchronousUserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId) throws RemoteException {
public void onUserSwitching(int newUserId) {
mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
.sendToTarget();
}
@@ -991,8 +952,7 @@ public abstract class BiometricServiceBase extends SystemService
}
}
private void removeLockoutResetCallback(
LockoutResetMonitor monitor) {
private void removeLockoutResetCallback(LockoutResetMonitor monitor) {
mLockoutMonitors.remove(monitor);
}
}

View File

@@ -31,7 +31,7 @@ import java.util.NoSuchElementException;
* the current client. Subclasses are responsible for coordinating the interaction with
* the biometric's HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
*/
public abstract class ClientMonitor extends LoggableMonitor implements IBinder.DeathRecipient {
public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinder.DeathRecipient {
private static final String TAG = "Biometrics/ClientMonitor";
protected static final boolean DEBUG = BiometricServiceBase.DEBUG;
@@ -51,31 +51,26 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D
void onClientFinished(ClientMonitor clientMonitor);
}
protected final FinishCallback mFinishCallback;
private final Context mContext;
@NonNull private final Context mContext;
private final int mTargetUserId;
// True if client does not have MANAGE_FINGERPRINT permission
private final boolean mIsRestricted;
private final String mOwner;
@NonNull private final String mOwner;
private final int mSensorId; // sensorId as configured by the framework
private IBinder mToken;
private ClientMonitorCallbackConverter mListener;
@Nullable private IBinder mToken;
@Nullable private ClientMonitorCallbackConverter mListener;
// Currently only used for authentication client. The cookie generated by BiometricService
// is never 0.
private final int mCookie;
boolean mAlreadyDone;
@NonNull protected T mDaemon;
@NonNull protected FinishCallback mFinishCallback;
/**
* @param finishCallback used to notify the ClientMonitor's holder when its lifecycle has
* completed and can be removed from the scheduler
* @param context system_server context
* @param token a unique token for the client
* @param listener recipient of related events (e.g. authentication)
* @param userId target user id for operation
* @param restricted whether or not client has the MANAGE_* permission
* permission
* @param owner name of the client that owns this
* @param cookie BiometricPrompt authentication cookie (to be moved into a subclass soon)
* @param sensorId ID of the sensor that the operation should be requested of
@@ -83,17 +78,15 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants
*/
public ClientMonitor(@NonNull FinishCallback finishCallback, @NonNull Context context,
IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
boolean restricted, @NonNull String owner, int cookie, int sensorId, int statsModality,
int statsAction, int statsClient) {
public ClientMonitor(@NonNull Context context, @Nullable IBinder token,
@Nullable ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
int cookie, int sensorId, int statsModality, int statsAction,
int statsClient) {
super(statsModality, statsAction, statsClient);
mFinishCallback = finishCallback;
mContext = context;
mToken = token;
mListener = listener;
mTargetUserId = userId;
mIsRestricted = restricted;
mOwner = owner;
mCookie = cookie;
mSensorId = sensorId;
@@ -111,11 +104,23 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D
return mCookie;
}
/**
* Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null).
* If such a problem is detected, the scheduler will not invoke
* {@link #start(Object, FinishCallback)}.
*/
public abstract void unableToStart();
/**
* Starts the ClientMonitor's lifecycle. Invokes {@link #startHalOperation()} when internal book
* keeping is complete.
* @param daemon reference to the HAL
* @param finishCallback invoked when the operation is complete (succeeds, fails, etc)
*/
public abstract void start();
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
mDaemon = daemon;
mFinishCallback = finishCallback;
}
/**
* Starts the HAL operation specific to the ClientMonitor subclass.
@@ -174,10 +179,6 @@ public abstract class ClientMonitor extends LoggableMonitor implements IBinder.D
return mListener;
}
public final boolean getIsRestricted() {
return mIsRestricted;
}
public final int getTargetUserId() {
return mTargetUserId;
}

View File

@@ -126,4 +126,17 @@ public final class ClientMonitorCallbackConverter {
mFingerprintServiceReceiver.onChallengeGenerated(challenge);
}
}
public void onFeatureSet(boolean success, int feature) throws RemoteException {
if (mFaceServiceReceiver != null) {
mFaceServiceReceiver.onFeatureSet(success, feature);
}
}
public void onFeatureGet(boolean success, int feature, boolean value)
throws RemoteException {
if (mFaceServiceReceiver != null) {
mFaceServiceReceiver.onFeatureGet(success, feature, value);
}
}
}

View File

@@ -29,7 +29,7 @@ import java.util.Arrays;
/**
* A class to keep track of the enrollment state for a given client.
*/
public abstract class EnrollClient extends AcquisitionClient {
public abstract class EnrollClient<T> extends AcquisitionClient<T> {
private static final String TAG = "Biometrics/EnrollClient";
@@ -41,14 +41,13 @@ public abstract class EnrollClient extends AcquisitionClient {
private long mEnrollmentStartTimeMs;
private boolean mAlreadyCancelled;
public EnrollClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, boolean restricted, String owner,
@NonNull BiometricUtils utils, int timeoutSec, int statsModality, int sensorId,
public EnrollClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
int timeoutSec, int statsModality, int sensorId,
boolean shouldVibrate) {
super(finishCallback, context, token, listener, userId, restricted, owner, 0 /* cookie */,
sensorId, statsModality, BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN);
super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, statsModality,
BiometricsProtoEnums.ACTION_ENROLL, BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec;
@@ -88,7 +87,9 @@ public abstract class EnrollClient extends AcquisitionClient {
}
@Override
public void start() {
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
mEnrollmentStartTimeMs = System.currentTimeMillis();
startHalOperation();
}

View File

@@ -16,27 +16,39 @@
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
public abstract class GenerateChallengeClient extends ClientMonitor {
public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> {
private static final String TAG = "GenerateChallengeClient";
protected long mChallenge;
public GenerateChallengeClient(FinishCallback finishCallback, Context context, IBinder token,
public GenerateChallengeClient(Context context, IBinder token,
ClientMonitorCallbackConverter listener, String owner, int sensorId) {
super(finishCallback, context, token, listener, 0 /* userId */, false /* restricted */,
owner, 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
super(context, token, listener, 0 /* userId */, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
}
@Override
public void start() {
public void unableToStart() {
try {
getListener().onChallengeGenerated(0L);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send error", e);
}
}
@Override
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
startHalOperation();
try {
getListener().onChallengeGenerated(mChallenge);

View File

@@ -37,8 +37,8 @@ import java.util.List;
* 2) The HAL and Framework are not in sync, and
* {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/
*/
public abstract class InternalCleanupClient extends ClientMonitor implements EnumerateConsumer,
RemovalConsumer {
public abstract class InternalCleanupClient<T> extends ClientMonitor<T>
implements EnumerateConsumer, RemovalConsumer {
private static final String TAG = "Biometrics/InternalCleanupClient";
@@ -58,17 +58,17 @@ public abstract class InternalCleanupClient extends ClientMonitor implements Enu
private final ArrayList<UserTemplate> mUnknownHALTemplates = new ArrayList<>();
private final BiometricUtils mBiometricUtils;
private final List<? extends BiometricAuthenticator.Identifier> mEnrolledList;
private ClientMonitor mCurrentTask;
private ClientMonitor<T> mCurrentTask;
private final FinishCallback mEnumerateFinishCallback = clientMonitor -> {
final List<BiometricAuthenticator.Identifier> unknownHALTemplates =
((InternalEnumerateClient) mCurrentTask).getUnknownHALTemplates();
((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates();
if (!unknownHALTemplates.isEmpty()) {
Slog.w(TAG, "Adding " + unknownHALTemplates.size() + " templates for deletion");
}
for (int i = 0; i < unknownHALTemplates.size(); i++) {
mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplates.get(i),
for (BiometricAuthenticator.Identifier unknownHALTemplate : unknownHALTemplates) {
mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplate,
mCurrentTask.getTargetUserId()));
}
@@ -85,22 +85,20 @@ public abstract class InternalCleanupClient extends ClientMonitor implements Enu
mFinishCallback.onClientFinished(this);
};
protected abstract InternalEnumerateClient getEnumerateClient(FinishCallback finishCallback,
Context context, IBinder token, int userId, boolean restricted, String owner,
protected abstract InternalEnumerateClient<T> getEnumerateClient(Context context, IBinder token,
int userId, String owner,
List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils,
int sensorId, int statsModality);
int sensorId);
protected abstract RemovalClient getRemovalClient(FinishCallback finishCallback,
Context context, IBinder token, int biometricId, int userId, boolean restricted,
String owner, BiometricUtils utils, int sensorId, int statsModality);
protected abstract RemovalClient<T> getRemovalClient(Context context, IBinder token,
int biometricId, int userId, String owner, BiometricUtils utils, int sensorId);
protected InternalCleanupClient(@NonNull FinishCallback finishCallback,
@NonNull Context context, int userId, boolean restricted,
protected InternalCleanupClient(@NonNull Context context, int userId,
@NonNull String owner, int sensorId, int statsModality,
@NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
@NonNull BiometricUtils utils) {
super(finishCallback, context, null /* token */, null /* ClientMonitorCallbackConverter */,
userId, restricted, owner, 0 /* cookie */, sensorId, statsModality,
super(context, null /* token */, null /* ClientMonitorCallbackConverter */,
userId, owner, 0 /* cookie */, sensorId, statsModality,
BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mEnrolledList = enrolledList;
@@ -109,22 +107,28 @@ public abstract class InternalCleanupClient extends ClientMonitor implements Enu
private void startCleanupUnknownHalTemplates() {
UserTemplate template = mUnknownHALTemplates.get(0);
mUnknownHALTemplates.remove(template);
mCurrentTask = getRemovalClient(mRemoveFinishCallback, getContext(), getToken(),
template.mIdentifier.getBiometricId(), template.mUserId, getIsRestricted(),
getContext().getPackageName(), mBiometricUtils, getSensorId(), mStatsModality);
mCurrentTask = getRemovalClient(getContext(), getToken(),
template.mIdentifier.getBiometricId(), template.mUserId,
getContext().getPackageName(), mBiometricUtils, getSensorId());
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
mStatsModality,
BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
mCurrentTask.start();
mCurrentTask.start(mDaemon, mRemoveFinishCallback);
}
@Override
public void start() {
public void unableToStart() {
// nothing to do here
}
@Override
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
// Start enumeration. Removal will start if necessary, when enumeration is completed.
mCurrentTask = getEnumerateClient(mEnumerateFinishCallback, getContext(), getToken(),
getTargetUserId(), getIsRestricted(), getOwnerString(), mEnrolledList,
mBiometricUtils, getSensorId(), mStatsModality);
mCurrentTask.start();
mCurrentTask = getEnumerateClient(getContext(), getToken(), getTargetUserId(),
getOwnerString(), mEnrolledList, mBiometricUtils, getSensorId());
mCurrentTask.start(daemon, mEnumerateFinishCallback);
}
@Override

View File

@@ -31,7 +31,8 @@ import java.util.List;
/**
* Internal class to help clean up unknown templates in the HAL and Framework
*/
public abstract class InternalEnumerateClient extends ClientMonitor implements EnumerateConsumer {
public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
implements EnumerateConsumer {
private static final String TAG = "Biometrics/InternalEnumerateClient";
@@ -42,16 +43,14 @@ public abstract class InternalEnumerateClient extends ClientMonitor implements E
// List of templates to remove from the HAL
private List<BiometricAuthenticator.Identifier> mUnknownHALTemplates = new ArrayList<>();
protected InternalEnumerateClient(@NonNull FinishCallback finishCallback,
@NonNull Context context, @NonNull IBinder token, int userId, boolean restricted,
protected InternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId,
@NonNull String owner,
@NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
@NonNull BiometricUtils utils, int sensorId, int statsModality) {
// Internal enumerate does not need to send results to anyone. Cleanup (enumerate + remove)
// is all done internally.
super(finishCallback, context, token, null /* ClientMonitorCallbackConverter */, userId,
restricted, owner, 0 /* cookie */, sensorId, statsModality,
BiometricsProtoEnums.ACTION_ENUMERATE,
super(context, token, null /* ClientMonitorCallbackConverter */, userId, owner,
0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENUMERATE,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mEnrolledList = enrolledList;
mUtils = utils;
@@ -68,7 +67,14 @@ public abstract class InternalEnumerateClient extends ClientMonitor implements E
}
@Override
public void start() {
public void unableToStart() {
// Nothing to do here
}
@Override
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
// The biometric template ids will be removed when we get confirmation from the HAL
startHalOperation();
}

View File

@@ -27,26 +27,31 @@ import android.util.Slog;
/**
* A class to keep track of the remove state for a given client.
*/
public abstract class RemovalClient extends ClientMonitor implements RemovalConsumer {
public abstract class RemovalClient<T> extends ClientMonitor<T> implements RemovalConsumer {
private static final String TAG = "Biometrics/RemovalClient";
protected final int mBiometricId;
private final BiometricUtils mBiometricUtils;
public RemovalClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
int biometricId, int userId, boolean restricted, @NonNull String owner,
@NonNull BiometricUtils utils, int sensorId, int statsModality) {
super(finishCallback, context, token, listener, userId, restricted, owner, 0 /* cookie */,
sensorId, statsModality, BiometricsProtoEnums.ACTION_REMOVE,
BiometricsProtoEnums.CLIENT_UNKNOWN);
public RemovalClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
@NonNull String owner, @NonNull BiometricUtils utils, int sensorId, int statsModality) {
super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, statsModality,
BiometricsProtoEnums.ACTION_REMOVE, BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricId = biometricId;
mBiometricUtils = utils;
}
@Override
public void start() {
public void unableToStart() {
// Nothing to do here
}
@Override
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
// The biometric template ids will be removed when we get confirmation from the HAL
startHalOperation();
}

View File

@@ -16,22 +16,28 @@
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
public abstract class RevokeChallengeClient extends ClientMonitor {
public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> {
public RevokeChallengeClient(FinishCallback finishCallback, Context context, IBinder token,
String owner, int sensorId) {
super(finishCallback, context, token, null /* listener */, 0 /* userId */,
false /* restricted */, owner, 0 /* cookie */, sensorId,
public RevokeChallengeClient(Context context, IBinder token, String owner, int sensorId) {
super(context, token, null /* listener */, 0 /* userId */, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
}
@Override
public void start() {
public void unableToStart() {
// Nothing to do here
}
@Override
public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
startHalOperation();
mFinishCallback.onClientFinished(this);
}

View File

@@ -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;
@@ -93,18 +86,6 @@ class FaceAuthenticationClient extends AuthenticationClient {
R.array.config_face_acquire_vendor_keyguard_ignorelist);
}
@Override
public void start() {
mStarted = true;
super.start();
}
@Override
public void cancel() {
mStarted = false;
super.cancel();
}
@Override
protected void startHalOperation() {
try {
@@ -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;

View File

@@ -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.
@@ -67,6 +68,12 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
return mFaceService.hasEnrolledFaces(userId, opPackageName);
}
@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);

View File

@@ -16,8 +16,11 @@
package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.Status;
import android.hardware.face.FaceManager;
@@ -39,24 +42,22 @@ import java.util.Arrays;
* Face-specific enroll client supporting the {@link android.hardware.biometrics.face.V1_0}
* and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
*/
public class FaceEnrollClient extends EnrollClient {
public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
private static final String TAG = "FaceEnrollClient";
private final IBiometricsFace mDaemon;
private final int[] mDisabledFeatures;
private final NativeHandle mSurfaceHandle;
private final int[] mEnrollIgnoreList;
private final int[] mEnrollIgnoreListVendor;
@NonNull private final int[] mDisabledFeatures;
@Nullable private final NativeHandle mSurfaceHandle;
@NonNull private final int[] mEnrollIgnoreList;
@NonNull private final int[] mEnrollIgnoreListVendor;
FaceEnrollClient(FinishCallback finishCallback, Context context, IBiometricsFace daemon,
IBinder token, ClientMonitorCallbackConverter listener, int userId,
byte[] hardwareAuthToken, boolean restricted, String owner, BiometricUtils utils,
int[] disabledFeatures, int timeoutSec, int statsModality, NativeHandle surfaceHandle,
FaceEnrollClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
@NonNull int[] disabledFeatures, int timeoutSec, @Nullable NativeHandle surfaceHandle,
int sensorId) {
super(finishCallback, context, token, listener, userId, hardwareAuthToken, restricted,
owner, utils, timeoutSec, statsModality, sensorId, false /* shouldVibrate */);
mDaemon = daemon;
super(context, token, listener, userId, hardwareAuthToken, owner, utils, timeoutSec,
BiometricsProtoEnums.MODALITY_FACE, sensorId, false /* shouldVibrate */);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
mSurfaceHandle = surfaceHandle;
mEnrollIgnoreList = getContext().getResources()

View File

@@ -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

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.OptionalBool;
import android.hardware.biometrics.face.V1_0.Status;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
/**
* Face-specific getFeature client supporting the {@link android.hardware.biometrics.face.V1_0}
* and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
*/
public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
private static final String TAG = "FaceGetFeatureClient";
private final int mFeature;
private final int mFaceId;
FaceGetFeatureClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
int sensorId, int feature, int faceId) {
super(context, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mFeature = feature;
mFaceId = faceId;
}
@Override
public void unableToStart() {
try {
getListener().onFeatureGet(false /* success */, mFeature, false /* value */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send error", e);
}
}
@Override
public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
startHalOperation();
}
@Override
protected void startHalOperation() {
try {
final OptionalBool result = mDaemon.getFeature(mFeature, mFaceId);
getListener().onFeatureGet(result.status == Status.OK, mFeature, result.value);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to getFeature", e);
}
mFinishCallback.onClientFinished(this);
}
@Override
protected void stopHalOperation() {
// Not supported for GetFeature
}
}

View File

@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.os.IBinder;
@@ -34,36 +35,30 @@ import java.util.List;
* {@link android.hardware.biometrics.face.V1_0} and {@link android.hardware.biometrics.face.V1_1}
* HIDL interfaces.
*/
class FaceInternalCleanupClient extends InternalCleanupClient {
private final IBiometricsFace mDaemon;
class FaceInternalCleanupClient extends InternalCleanupClient<IBiometricsFace> {
FaceInternalCleanupClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBiometricsFace daemon, int userId, boolean restricted, String owner,
int sensorId, int statsModality,
@NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
FaceInternalCleanupClient(@NonNull Context context, int userId, @NonNull String owner,
int sensorId, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
@NonNull BiometricUtils utils) {
super(finishCallback, context, userId, restricted, owner, sensorId, statsModality,
enrolledList, utils);
mDaemon = daemon;
super(context, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FACE, enrolledList,
utils);
}
@Override
protected InternalEnumerateClient getEnumerateClient(FinishCallback finishCallback,
Context context, IBinder token, int userId, boolean restricted, String owner,
protected InternalEnumerateClient<IBiometricsFace> getEnumerateClient(Context context,
IBinder token, int userId, String owner,
List<? extends BiometricAuthenticator.Identifier> enrolledList,
BiometricUtils utils, int sensorId, int statsModality) {
return new FaceInternalEnumerateClient(finishCallback, context, mDaemon, token, userId,
restricted, owner, enrolledList, utils, sensorId, statsModality);
BiometricUtils utils, int sensorId) {
return new FaceInternalEnumerateClient(context, token, userId, owner, enrolledList, utils,
sensorId);
}
@Override
protected RemovalClient getRemovalClient(FinishCallback finishCallback, Context context,
IBinder token, int biometricId, int userId, boolean restricted, String owner,
BiometricUtils utils, int sensorId, int statsModality) {
protected RemovalClient<IBiometricsFace> getRemovalClient(Context context, IBinder token,
int biometricId, int userId, String owner, BiometricUtils utils, int sensorId) {
// Internal remove does not need to send results to anyone. Cleanup (enumerate + remove)
// is all done internally.
return new FaceRemovalClient(finishCallback, context, mDaemon, token,
null /* ClientMonitorCallbackConverter */, biometricId, userId, restricted,
owner, utils, sensorId, statsModality);
return new FaceRemovalClient(context, token, null /* ClientMonitorCallbackConverter */,
biometricId, userId, owner, utils, sensorId);
}
}

View File

@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.os.IBinder;
import android.os.RemoteException;
@@ -34,19 +35,15 @@ import java.util.List;
* {@link android.hardware.biometrics.face.V1_0} and {@link android.hardware.biometrics.face.V1_1}
* HIDL interfaces.
*/
class FaceInternalEnumerateClient extends InternalEnumerateClient {
class FaceInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFace> {
private static final String TAG = "FaceInternalEnumerateClient";
private final IBiometricsFace mDaemon;
FaceInternalEnumerateClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBiometricsFace daemon, @NonNull IBinder token, int userId, boolean restricted,
FaceInternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId,
@NonNull String owner,
@NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
@NonNull BiometricUtils utils, int sensorId, int statsModality) {
super(finishCallback, context, token, userId, restricted, owner, enrolledList, utils,
sensorId, statsModality);
mDaemon = daemon;
@NonNull BiometricUtils utils, int sensorId) {
super(context, token, userId, owner, enrolledList, utils, sensorId,
BiometricsProtoEnums.MODALITY_FACE);
}
@Override

View File

@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.os.IBinder;
import android.os.RemoteException;
@@ -31,18 +32,14 @@ import com.android.server.biometrics.sensors.RemovalClient;
* Face-specific removal client supporting the {@link android.hardware.biometrics.face.V1_0}
* and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
*/
class FaceRemovalClient extends RemovalClient {
class FaceRemovalClient extends RemovalClient<IBiometricsFace> {
private static final String TAG = "FaceRemovalClient";
private final IBiometricsFace mDaemon;
FaceRemovalClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBiometricsFace daemon, @NonNull IBinder token,
FaceRemovalClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
boolean restricted, @NonNull String owner, @NonNull BiometricUtils utils, int sensorId,
int statsModality) {
super(finishCallback, context, token, listener, biometricId, userId, restricted, owner,
utils, sensorId, statsModality);
mDaemon = daemon;
@NonNull String owner, @NonNull BiometricUtils utils, int sensorId) {
super(context, token, listener, biometricId, userId, owner, utils, sensorId,
BiometricsProtoEnums.MODALITY_FACE);
}
@Override

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.sensors.ClientMonitor;
import java.util.ArrayList;
/**
* Face-specific resetLockout client supporting the {@link android.hardware.biometrics.face.V1_0}
* and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
*/
public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> {
private static final String TAG = "FaceResetLockoutClient";
private final ArrayList<Byte> mHardwareAuthToken;
FaceResetLockoutClient(@NonNull Context context, int userId, String owner, int sensorId,
byte[] hardwareAuthToken) {
super(context, null /* token */, null /* listener */, userId, owner, 0 /* cookie */,
sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mHardwareAuthToken = new ArrayList<>();
for (byte b : hardwareAuthToken) {
mHardwareAuthToken.add(b);
}
}
@Override
public void unableToStart() {
// Nothing to do here
}
@Override
public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
startHalOperation();
}
@Override
protected void startHalOperation() {
try {
mDaemon.resetLockout(mHardwareAuthToken);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to reset lockout", e);
}
mFinishCallback.onClientFinished(this);
}
@Override
protected void stopHalOperation() {
// Not supported for resetLockout
}
}

View File

@@ -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

View File

@@ -32,8 +32,6 @@ import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
import android.hardware.biometrics.face.V1_0.OptionalBool;
import android.hardware.biometrics.face.V1_0.Status;
import android.hardware.face.Face;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
@@ -87,7 +85,7 @@ import java.util.List;
*
* @hide
*/
public class FaceService extends BiometricServiceBase {
public class FaceService extends BiometricServiceBase<IBiometricsFace> {
protected static final String TAG = "FaceService";
private static final boolean DEBUG = true;
@@ -111,19 +109,12 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public void generateChallenge(IBinder token, IFaceServiceReceiver receiver,
String opPackageName) throws RemoteException {
String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
final IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to generateChallenge, daemon null");
receiver.onChallengeGenerated(0L);
return;
}
final GenerateChallengeClient client = new FaceGenerateChallengeClient(
mClientFinishCallback, getContext(), daemon, token,
new ClientMonitorCallbackConverter(receiver), opPackageName, getSensorId());
final GenerateChallengeClient client = new FaceGenerateChallengeClient(getContext(),
token, new ClientMonitorCallbackConverter(receiver), opPackageName,
getSensorId());
generateChallengeInternal(client);
}
@@ -131,14 +122,8 @@ public class FaceService extends BiometricServiceBase {
public void revokeChallenge(IBinder token, String owner) {
checkPermission(MANAGE_BIOMETRIC);
final IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to revokeChallenge, daemon null");
return;
}
final RevokeChallengeClient client = new FaceRevokeChallengeClient(
mClientFinishCallback, getContext(), daemon, token, owner, getSensorId());
final RevokeChallengeClient client = new FaceRevokeChallengeClient(getContext(), token,
owner, getSensorId());
// TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
if (getCurrentClient() == null) {
@@ -153,37 +138,27 @@ public class FaceService extends BiometricServiceBase {
}
@Override // Binder call
public void enroll(int userId, final IBinder token, final byte[] cryptoToken,
public void enroll(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures, Surface surface) throws RemoteException {
final int[] disabledFeatures, Surface surface) {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(userId, opPackageName);
updateActiveGroup(userId);
mHandler.post(() -> {
mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
UserHandle.CURRENT);
});
final IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to enroll, daemon null");
receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
return;
}
final boolean restricted = isRestricted();
final EnrollClient client = new FaceEnrollClient(mClientFinishCallback, getContext(),
daemon, token, new ClientMonitorCallbackConverter(receiver),
userId, cryptoToken, restricted, opPackageName, getBiometricUtils(),
disabledFeatures, ENROLL_TIMEOUT_SEC, statsModality(),
final EnrollClient client = new FaceEnrollClient(getContext(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, getBiometricUtils(), disabledFeatures, ENROLL_TIMEOUT_SEC,
convertSurfaceToNativeHandle(surface), getSensorId());
enrollInternal(client, userId);
}
@Override // Binder call
public void enrollRemotely(int userId, final IBinder token, final byte[] cryptoToken,
public void enrollRemotely(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures) {
checkPermission(MANAGE_BIOMETRIC);
@@ -198,27 +173,18 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public void authenticate(final IBinder token, final long opId, int userId,
final IFaceServiceReceiver receiver, final int flags,
final String opPackageName) throws RemoteException {
final IFaceServiceReceiver receiver, final String opPackageName) {
checkPermission(USE_BIOMETRIC_INTERNAL);
updateActiveGroup(userId, opPackageName);
final IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to authenticate, daemon null");
receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
return;
}
updateActiveGroup(userId);
final boolean restricted = isRestricted();
final int statsClient = isKeyguard(opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD
: BiometricsProtoEnums.CLIENT_UNKNOWN;
final AuthenticationClient client = new FaceAuthenticationClient(mClientFinishCallback,
getContext(), daemon, token, new ClientMonitorCallbackConverter(receiver),
userId, opId, restricted, opPackageName, 0 /* cookie */,
false /* requireConfirmation */, getSensorId(), isStrongBiometric(),
statsClient, mTaskStackListener, mLockoutTracker, mUsageStats);
final AuthenticationClient client = new FaceAuthenticationClient(getContext(), token,
new ClientMonitorCallbackConverter(receiver), userId, opId, restricted,
opPackageName, 0 /* cookie */, false /* requireConfirmation */, getSensorId(),
isStrongBiometric(), statsClient, mTaskStackListener, mLockoutTracker,
mUsageStats);
authenticateInternal(client, opPackageName);
}
@@ -226,23 +192,14 @@ public class FaceService extends BiometricServiceBase {
public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long opId,
int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, int callingUid, int callingPid,
int callingUserId) throws RemoteException {
int callingUserId) {
checkPermission(USE_BIOMETRIC_INTERNAL);
updateActiveGroup(userId, opPackageName);
final IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to prepare for authentication, daemon null");
sensorReceiver.onError(getSensorId(), cookie,
BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
return;
}
updateActiveGroup(userId);
final boolean restricted = true; // BiometricPrompt is always restricted
final AuthenticationClient client = new FaceAuthenticationClient(mClientFinishCallback,
getContext(), daemon, token, new ClientMonitorCallbackConverter(sensorReceiver),
userId, opId, restricted, opPackageName, cookie, requireConfirmation,
getSensorId(), isStrongBiometric(),
final AuthenticationClient client = new FaceAuthenticationClient(getContext(), token,
new ClientMonitorCallbackConverter(sensorReceiver), userId, opId, restricted,
opPackageName, cookie, requireConfirmation, getSensorId(), isStrongBiometric(),
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, mTaskStackListener,
mLockoutTracker, mUsageStats);
authenticateInternal(client, opPackageName, callingUid, callingPid,
@@ -272,34 +229,23 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public void remove(final IBinder token, final int faceId, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName)
throws RemoteException {
final IFaceServiceReceiver receiver, final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(userId, opPackageName);
updateActiveGroup(userId);
if (token == null) {
Slog.w(TAG, "remove(): token is null");
return;
}
final IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to remove, daemon null");
receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
return;
}
final boolean restricted = isRestricted();
final RemovalClient client = new FaceRemovalClient(mClientFinishCallback, getContext(),
daemon, token, new ClientMonitorCallbackConverter(receiver), faceId, userId,
restricted, opPackageName, getBiometricUtils(), getSensorId(), statsModality());
final RemovalClient client = new FaceRemovalClient(getContext(), token,
new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName,
getBiometricUtils(), getSensorId());
removeInternal(client);
}
@Override
public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
throws RemoteException {
public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback) {
checkPermission(USE_BIOMETRIC_INTERNAL);
FaceService.super.addLockoutResetCallback(callback);
}
@@ -369,6 +315,12 @@ public class FaceService extends BiometricServiceBase {
return FaceService.this.hasEnrolledBiometrics(userId);
}
@Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
checkPermission(USE_BIOMETRIC_INTERNAL);
return mLockoutTracker.getLockoutModeForUser(userId);
}
@Override // Binder call
public long getAuthenticatorId(int callingUserId) {
checkPermission(USE_BIOMETRIC_INTERNAL);
@@ -386,65 +338,49 @@ public class FaceService extends BiometricServiceBase {
Slog.d(TAG, "Resetting lockout for user: " + userId);
updateActiveGroup(userId, null /* opPackageName */);
try {
final ArrayList<Byte> token = new ArrayList<>();
for (int i = 0; i < hardwareAuthToken.length; i++) {
token.add(hardwareAuthToken[i]);
}
mDaemon.resetLockout(token);
} catch (RemoteException e) {
Slog.e(getTag(), "Unable to reset lockout", e);
}
updateActiveGroup(userId);
final FaceResetLockoutClient client = new FaceResetLockoutClient(getContext(),
userId, getContext().getOpPackageName(), getSensorId(), hardwareAuthToken);
startClient(client, true /* initiatedByClient */);
});
}
@Override
public void setFeature(int userId, int feature, boolean enabled, final byte[] token,
IFaceServiceReceiver receiver, final String opPackageName) {
public void setFeature(final IBinder token, int userId, int feature, boolean enabled,
final byte[] hardwareAuthToken, IFaceServiceReceiver receiver,
final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
mHandler.post(() -> {
if (DEBUG) {
Slog.d(TAG, "setFeature for user(" + userId + ")");
}
updateActiveGroup(userId, opPackageName);
updateActiveGroup(userId);
if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
return;
}
final ArrayList<Byte> byteToken = new ArrayList<>();
for (int i = 0; i < token.length; i++) {
byteToken.add(token[i]);
}
// TODO: Support multiple faces
final int faceId = getFirstTemplateForUser(mCurrentUserId);
if (mDaemon != null) {
try {
final int result = mDaemon.setFeature(feature, enabled, byteToken, faceId);
receiver.onFeatureSet(result == Status.OK, feature);
} catch (RemoteException e) {
Slog.e(getTag(), "Unable to set feature: " + feature
+ " to enabled:" + enabled, e);
}
}
final FaceSetFeatureClient client = new FaceSetFeatureClient(getContext(),
token, new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
getSensorId(), feature, enabled, hardwareAuthToken, faceId);
startClient(client, true /* initiatedByClient */);
});
}
@Override
public void getFeature(int userId, int feature, IFaceServiceReceiver receiver,
final String opPackageName) {
public void getFeature(final IBinder token, int userId, int feature,
IFaceServiceReceiver receiver, final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
mHandler.post(() -> {
if (DEBUG) {
Slog.d(TAG, "getFeature for user(" + userId + ")");
}
updateActiveGroup(userId, opPackageName);
updateActiveGroup(userId);
// This should ideally return tri-state, but the user isn't shown settings unless
// they are enrolled so it's fine for now.
if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
@@ -455,31 +391,14 @@ public class FaceService extends BiometricServiceBase {
// TODO: Support multiple faces
final int faceId = getFirstTemplateForUser(mCurrentUserId);
if (mDaemon != null) {
try {
OptionalBool result = mDaemon.getFeature(feature, faceId);
receiver.onFeatureGet(result.status == Status.OK, feature, result.value);
} catch (RemoteException e) {
Slog.e(getTag(), "Unable to getRequireAttention", e);
}
}
final FaceGetFeatureClient client = new FaceGetFeatureClient(getContext(), token,
new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
getSensorId(), feature, faceId);
startClient(client, true /* initiatedByClient */);
});
}
@Override
public void userActivity() {
checkPermission(MANAGE_BIOMETRIC);
if (mDaemon != null) {
try {
mDaemon.userActivity();
} catch (RemoteException e) {
Slog.e(getTag(), "Unable to send userActivity", e);
}
}
}
// TODO: Support multiple faces
private int getFirstTemplateForUser(int user) {
final List<Face> faces = FaceService.this.getEnrolledTemplates(user);
@@ -657,6 +576,11 @@ public class FaceService extends BiometricServiceBase {
return TAG;
}
@Override
protected IBiometricsFace getDaemon() {
return getFaceDaemon();
}
@Override
protected BiometricUtils getBiometricUtils() {
return FaceUtils.getInstance();
@@ -683,12 +607,11 @@ public class FaceService extends BiometricServiceBase {
}
@Override
protected void updateActiveGroup(int userId, String clientPackage) {
protected void updateActiveGroup(int userId) {
IBiometricsFace daemon = getFaceDaemon();
if (daemon != null) {
try {
userId = getUserOrWorkProfileId(clientPackage, userId);
if (userId != mCurrentUserId) {
final File baseDir = Environment.getDataVendorDeDirectory(userId);
final File faceDir = new File(baseDir, FACE_DATA_DIR);
@@ -770,19 +693,10 @@ public class FaceService extends BiometricServiceBase {
@Override
protected void doTemplateCleanupForUser(int userId) {
final IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
Slog.e(TAG, "daemon null, skipping template cleanup");
return;
}
final boolean restricted = !hasPermission(getManageBiometricPermission());
final List<? extends BiometricAuthenticator.Identifier> enrolledList =
getEnrolledTemplates(userId);
final FaceInternalCleanupClient client = new FaceInternalCleanupClient(
mClientFinishCallback, getContext(), daemon, userId, restricted,
getContext().getOpPackageName(), getSensorId(), statsModality(), enrolledList,
getBiometricUtils());
final FaceInternalCleanupClient client = new FaceInternalCleanupClient(getContext(), userId,
getContext().getOpPackageName(), getSensorId(), enrolledList, getBiometricUtils());
cleanupInternal(client);
}
@@ -816,7 +730,7 @@ public class FaceService extends BiometricServiceBase {
if (DEBUG) Slog.v(TAG, "Face HAL id: " + halId);
if (halId != 0) {
loadAuthenticatorIds();
updateActiveGroup(ActivityManager.getCurrentUser(), null);
updateActiveGroup(ActivityManager.getCurrentUser());
doTemplateCleanupForUser(ActivityManager.getCurrentUser());
} else {
Slog.w(TAG, "Failed to open Face HAL!");

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.Status;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import java.util.ArrayList;
/**
* Face-specific setFeature client supporting the {@link android.hardware.biometrics.face.V1_0}
* and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
*/
public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> {
private static final String TAG = "FaceSetFeatureClient";
private final int mFeature;
private final boolean mEnabled;
private final ArrayList<Byte> mHardwareAuthToken;
private final int mFaceId;
FaceSetFeatureClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int sensorId, int feature, boolean enabled,
byte[] hardwareAuthToken, int faceId) {
super(context, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mFeature = feature;
mEnabled = enabled;
mFaceId = faceId;
mHardwareAuthToken = new ArrayList<>();
for (byte b : hardwareAuthToken) {
mHardwareAuthToken.add(b);
}
}
@Override
public void unableToStart() {
try {
getListener().onFeatureSet(false /* success */, mFeature);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send error", e);
}
}
@Override
public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) {
super.start(daemon, finishCallback);
startHalOperation();
mFinishCallback.onClientFinished(this);
}
@Override
protected void startHalOperation() {
try {
final int result = mDaemon.setFeature(mFeature, mEnabled, mHardwareAuthToken, mFaceId);
getListener().onFeatureSet(result == Status.OK, mFeature);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e);
}
}
@Override
protected void stopHalOperation() {
// Not supported for SetFeature
}
}

View File

@@ -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;
}

View File

@@ -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.
@@ -67,6 +68,12 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
return mFingerprintService.hasEnrolledFingerprints(userId, opPackageName);
}
@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);

View File

@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.os.IBinder;
import android.os.RemoteException;
@@ -33,20 +34,16 @@ import com.android.server.biometrics.sensors.EnrollClient;
* {@link android.hardware.biometrics.fingerprint.V2_1} and
* {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces.
*/
public class FingerprintEnrollClient extends EnrollClient {
public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint> {
private static final String TAG = "FingerprintEnrollClient";
private final IBiometricsFingerprint mDaemon;
FingerprintEnrollClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBiometricsFingerprint daemon, @NonNull IBinder token,
FingerprintEnrollClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, boolean restricted, @NonNull String owner,
@NonNull BiometricUtils utils, int timeoutSec, int statsModality,
int sensorId, boolean shouldVibrate) {
super(finishCallback, context, token, listener, userId, hardwareAuthToken, restricted,
owner, utils, timeoutSec, statsModality, sensorId, shouldVibrate);
mDaemon = daemon;
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
int timeoutSec, int sensorId) {
super(context, token, listener, userId, hardwareAuthToken, owner, utils, timeoutSec,
BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId, true /* shouldVibrate */);
}
@Override

View File

@@ -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

View File

@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.os.IBinder;
@@ -34,36 +35,31 @@ import java.util.List;
* {@link android.hardware.biometrics.fingerprint.V2_1} and
* {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces.
*/
class FingerprintInternalCleanupClient extends InternalCleanupClient {
private final IBiometricsFingerprint mDaemon;
class FingerprintInternalCleanupClient extends InternalCleanupClient<IBiometricsFingerprint> {
FingerprintInternalCleanupClient(@NonNull FinishCallback finishCallback,
@NonNull Context context, @NonNull IBiometricsFingerprint daemon, int userId,
boolean restricted, @NonNull String owner, int sensorId, int statsModality,
@NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
FingerprintInternalCleanupClient(@NonNull Context context,int userId, @NonNull String owner,
int sensorId, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
@NonNull BiometricUtils utils) {
super(finishCallback, context, userId, restricted, owner, sensorId, statsModality,
super(context, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FINGERPRINT,
enrolledList, utils);
mDaemon = daemon;
}
@Override
protected InternalEnumerateClient getEnumerateClient(FinishCallback finishCallback,
Context context, IBinder token, int userId, boolean restricted, String owner,
protected InternalEnumerateClient<IBiometricsFingerprint> getEnumerateClient(
Context context, IBinder token, int userId, String owner,
List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils,
int sensorId, int statsModality) {
return new FingerprintInternalEnumerateClient(finishCallback, context, mDaemon, token,
userId, restricted, owner, enrolledList, utils, sensorId, statsModality);
int sensorId) {
return new FingerprintInternalEnumerateClient(context, token, userId, owner, enrolledList,
utils, sensorId);
}
@Override
protected RemovalClient getRemovalClient(FinishCallback finishCallback, Context context,
IBinder token, int biometricId, int userId, boolean restricted, String owner,
BiometricUtils utils, int sensorId, int statsModality) {
protected RemovalClient<IBiometricsFingerprint> getRemovalClient(Context context, IBinder token,
int biometricId, int userId, String owner, BiometricUtils utils, int sensorId) {
// Internal remove does not need to send results to anyone. Cleanup (enumerate + remove)
// is all done internally.
return new FingerprintRemovalClient(finishCallback, context, mDaemon, token,
null /* ClientMonitorCallbackConverter */, biometricId, userId, restricted,
owner, utils, sensorId, statsModality);
return new FingerprintRemovalClient(context, token,
null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils,
sensorId);
}
}

View File

@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.os.IBinder;
import android.os.RemoteException;
@@ -34,19 +35,15 @@ import java.util.List;
* {@link android.hardware.biometrics.fingerprint.V2_1} and
* {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces.
*/
class FingerprintInternalEnumerateClient extends InternalEnumerateClient {
class FingerprintInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFingerprint> {
private static final String TAG = "FingerprintInternalEnumerateClient";
private final IBiometricsFingerprint mDaemon;
FingerprintInternalEnumerateClient(@NonNull FinishCallback finishCallback,
@NonNull Context context, @NonNull IBiometricsFingerprint daemon,
@NonNull IBinder token, int userId, boolean restricted, @NonNull String owner,
FingerprintInternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId,
@NonNull String owner,
@NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
@NonNull BiometricUtils utils, int sensorId, int statsModality) {
super(finishCallback, context, token, userId, restricted, owner, enrolledList, utils,
sensorId, statsModality);
mDaemon = daemon;
@NonNull BiometricUtils utils, int sensorId) {
super(context, token, userId, owner, enrolledList, utils, sensorId,
BiometricsProtoEnums.MODALITY_FINGERPRINT);
}
@Override

View File

@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,19 +33,14 @@ import com.android.server.biometrics.sensors.RemovalClient;
* {@link android.hardware.biometrics.fingerprint.V2_1} and
* {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces.
*/
class FingerprintRemovalClient extends RemovalClient {
class FingerprintRemovalClient extends RemovalClient<IBiometricsFingerprint> {
private static final String TAG = "FingerprintRemovalClient";
private final IBiometricsFingerprint mDaemon;
FingerprintRemovalClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
@NonNull IBiometricsFingerprint daemon, @NonNull IBinder token,
FingerprintRemovalClient(@NonNull Context context, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
boolean restricted, @NonNull String owner, @NonNull BiometricUtils utils, int sensorId,
int statsModality) {
super(finishCallback, context, token, listener, biometricId, userId, restricted, owner,
utils, sensorId, statsModality);
mDaemon = daemon;
@NonNull String owner, @NonNull BiometricUtils utils, int sensorId) {
super(context, token, listener, biometricId, userId, owner, utils, sensorId,
BiometricsProtoEnums.MODALITY_FINGERPRINT);
}
@Override

View File

@@ -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

View File

@@ -91,7 +91,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
*
* @hide
*/
public class FingerprintService extends BiometricServiceBase {
public class FingerprintService extends BiometricServiceBase<IBiometricsFingerprint> {
protected static final String TAG = "FingerprintService";
private static final boolean DEBUG = true;
@@ -109,19 +109,12 @@ public class FingerprintService extends BiometricServiceBase {
@Override // Binder call
public void generateChallenge(IBinder token, IFingerprintServiceReceiver receiver,
String opPackageName) throws RemoteException {
String opPackageName) {
checkPermission(MANAGE_FINGERPRINT);
final IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to generateChallenge, daemon null");
receiver.onChallengeGenerated(0L);
return;
}
final GenerateChallengeClient client = new FingerprintGenerateChallengeClient(
mClientFinishCallback, getContext(), daemon, token,
new ClientMonitorCallbackConverter(receiver), opPackageName, getSensorId());
getContext(), token, new ClientMonitorCallbackConverter(receiver),
opPackageName, getSensorId());
generateChallengeInternal(client);
}
@@ -129,37 +122,21 @@ public class FingerprintService extends BiometricServiceBase {
public void revokeChallenge(IBinder token, String owner) {
checkPermission(MANAGE_FINGERPRINT);
final IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.e(TAG, "startPostEnroll: no fingerprint HAL!");
return;
}
final RevokeChallengeClient client = new FingerprintRevokeChallengeClient(
mClientFinishCallback, getContext(), daemon, token, owner, getSensorId());
final RevokeChallengeClient client = new FingerprintRevokeChallengeClient(getContext(),
token, owner, getSensorId());
revokeChallengeInternal(client);
}
@Override // Binder call
public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName, Surface surface) throws RemoteException {
final IFingerprintServiceReceiver receiver, final String opPackageName,
final Surface surface) {
checkPermission(MANAGE_FINGERPRINT);
updateActiveGroup(userId, opPackageName);
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,
opPackageName, getBiometricUtils(), ENROLL_TIMEOUT_SEC, getSensorId());
enrollInternal(client, userId);
}
@@ -172,17 +149,9 @@ public class FingerprintService extends BiometricServiceBase {
@Override // Binder call
public void authenticate(final IBinder token, final long opId, final int userId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName, Surface surface) throws RemoteException {
updateActiveGroup(userId, opPackageName);
final IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to authenticate, daemon null");
receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
return;
}
final IFingerprintServiceReceiver receiver, final String opPackageName,
final Surface surface) {
updateActiveGroup(userId);
final boolean isStrongBiometric;
final long ident = Binder.clearCallingIdentity();
@@ -195,9 +164,8 @@ public class FingerprintService extends BiometricServiceBase {
final boolean restricted = isRestricted();
final int statsClient = isKeyguard(opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD
: BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
final AuthenticationClient client = new FingerprintAuthenticationClient(
mClientFinishCallback, getContext(), daemon, token,
new ClientMonitorCallbackConverter(receiver), userId, opId, restricted,
final AuthenticationClient client = new FingerprintAuthenticationClient(getContext(),
token, new ClientMonitorCallbackConverter(receiver), userId, opId, restricted,
opPackageName, 0 /* cookie */, false /* requireConfirmation */, getSensorId(),
isStrongBiometric, surface, statsClient, mTaskStackListener, mLockoutTracker);
authenticateInternal(client, opPackageName);
@@ -209,21 +177,11 @@ public class FingerprintService extends BiometricServiceBase {
int cookie, int callingUid, int callingPid, int callingUserId,
Surface surface) throws RemoteException {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(userId, opPackageName);
final IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to prepare for authentication, daemon null");
sensorReceiver.onError(getSensorId(), cookie,
BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
return;
}
updateActiveGroup(userId);
final boolean restricted = true; // BiometricPrompt is always restricted
final AuthenticationClient client = new FingerprintAuthenticationClient(
mClientFinishCallback, getContext(), daemon, token,
new ClientMonitorCallbackConverter(sensorReceiver), userId, opId,
final AuthenticationClient client = new FingerprintAuthenticationClient(getContext(),
token, new ClientMonitorCallbackConverter(sensorReceiver), userId, opId,
restricted, opPackageName, cookie, false /* requireConfirmation */,
getSensorId(), isStrongBiometric(), surface,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, mTaskStackListener,
@@ -258,26 +216,16 @@ public class FingerprintService extends BiometricServiceBase {
final IFingerprintServiceReceiver receiver, final String opPackageName)
throws RemoteException {
checkPermission(MANAGE_FINGERPRINT);
updateActiveGroup(userId, opPackageName);
updateActiveGroup(userId);
if (token == null) {
Slog.w(TAG, "remove(): token is null");
return;
}
final IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.e(TAG, "Unable to remove, daemon null");
receiver.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
return;
}
final boolean restricted = isRestricted();
final RemovalClient client = new FingerprintRemovalClient(mClientFinishCallback,
getContext(), daemon, token, new ClientMonitorCallbackConverter(receiver),
fingerId, userId, restricted, opPackageName, getBiometricUtils(),
getSensorId(), statsModality());
final RemovalClient client = new FingerprintRemovalClient(getContext(), token,
new ClientMonitorCallbackConverter(receiver), fingerId, userId, opPackageName,
getBiometricUtils(), getSensorId());
removeInternal(client);
}
@@ -365,6 +313,12 @@ public class FingerprintService extends BiometricServiceBase {
return FingerprintService.this.hasEnrolledBiometrics(userId);
}
@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);
@@ -611,6 +565,11 @@ public class FingerprintService extends BiometricServiceBase {
return TAG;
}
@Override
protected IBiometricsFingerprint getDaemon() {
return getFingerprintDaemon();
}
@Override
protected BiometricUtils getBiometricUtils() {
return FingerprintUtils.getInstance();
@@ -635,12 +594,11 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override
protected void updateActiveGroup(int userId, String clientPackage) {
protected void updateActiveGroup(int userId) {
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon != null) {
try {
userId = getUserOrWorkProfileId(clientPackage, userId);
if (userId != mCurrentUserId) {
int firstSdkInt = Build.VERSION.FIRST_SDK_INT;
if (firstSdkInt < Build.VERSION_CODES.BASE) {
@@ -747,18 +705,10 @@ public class FingerprintService extends BiometricServiceBase {
@Override
protected void doTemplateCleanupForUser(int userId) {
final IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.e(TAG, "daemon null, skipping template cleanup");
return;
}
final boolean restricted = !hasPermission(getManageBiometricPermission());
final List<? extends BiometricAuthenticator.Identifier> enrolledList =
getEnrolledTemplates(userId);
final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient(
mClientFinishCallback, getContext(), daemon, userId, restricted,
getContext().getOpPackageName(), getSensorId(), statsModality(), enrolledList,
getContext(), userId, getContext().getOpPackageName(), getSensorId(), enrolledList,
getBiometricUtils());
cleanupInternal(client);
}
@@ -793,7 +743,7 @@ public class FingerprintService extends BiometricServiceBase {
if (halId != 0) {
loadAuthenticatorIds();
final int userId = ActivityManager.getCurrentUser();
updateActiveGroup(userId, null);
updateActiveGroup(userId);
doTemplateCleanupForUser(userId);
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");

View File

@@ -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.
@@ -62,6 +63,12 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
return false;
}
@Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId)
throws RemoteException {
return LockoutTracker.LOCKOUT_NONE;
}
@Override
public void resetLockout(int userId, byte[] hardwareAuthToken) throws RemoteException {
}

View File

@@ -84,6 +84,11 @@ public class IrisService extends BiometricServiceBase {
return TAG;
}
@Override
protected Object getDaemon() {
return null;
}
@Override
protected BiometricUtils getBiometricUtils() {
return null;
@@ -95,7 +100,7 @@ public class IrisService extends BiometricServiceBase {
}
@Override
protected void updateActiveGroup(int userId, String clientPackage) {
protected void updateActiveGroup(int userId) {
}

View File

@@ -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;
@@ -824,6 +825,62 @@ public class BiometricServiceTest {
assertNull(mBiometricService.mCurrentAuthSession);
}
@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;
@@ -1198,6 +1255,29 @@ public class BiometricServiceTest {
invokeCanAuthenticate(mBiometricService, authenticators));
}
@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
@@ -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);
}

View File

@@ -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++) {

View File

@@ -50,6 +50,11 @@ public class BiometricServiceBaseTest {
return null;
}
@Override
protected Object getDaemon() {
return null;
}
@Override
protected BiometricUtils getBiometricUtils() {
return null;
@@ -61,7 +66,7 @@ public class BiometricServiceBaseTest {
}
@Override
protected void updateActiveGroup(int userId, String clientPackage) {
protected void updateActiveGroup(int userId) {
}
@Override