Merge changes from topic "more-cancel-sc-qpr1-dev" into sc-qpr1-dev

* changes:
  Add requestId to authentication entry points.
  Check cancel status whenever cookies are received.
This commit is contained in:
Joe Bolinger
2021-09-01 22:06:13 +00:00
committed by Android (Google) Code Review
43 changed files with 713 additions and 309 deletions

View File

@@ -438,9 +438,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
} }
private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener { private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
private final long mAuthRequestId;
OnAuthenticationCancelListener(long id) {
mAuthRequestId = id;
}
@Override @Override
public void onCancel() { public void onCancel() {
cancelAuthentication(); Log.d(TAG, "Cancel BP authentication requested for: " + mAuthRequestId);
cancelAuthentication(mAuthRequestId);
} }
} }
@@ -853,10 +860,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
* @param userId The user to authenticate * @param userId The user to authenticate
* @param operationId The keystore operation associated with authentication * @param operationId The keystore operation associated with authentication
* *
* @return A requestId that can be used to cancel this operation.
*
* @hide * @hide
*/ */
@RequiresPermission(USE_BIOMETRIC_INTERNAL) @RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void authenticateUserForOperation( public long authenticateUserForOperation(
@NonNull CancellationSignal cancel, @NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor, @NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback, @NonNull AuthenticationCallback callback,
@@ -871,7 +880,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
if (callback == null) { if (callback == null) {
throw new IllegalArgumentException("Must supply a callback"); throw new IllegalArgumentException("Must supply a callback");
} }
authenticateInternal(operationId, cancel, executor, callback, userId);
return authenticateInternal(operationId, cancel, executor, callback, userId);
} }
/** /**
@@ -1002,10 +1012,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId()); authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
} }
private void cancelAuthentication() { private void cancelAuthentication(long requestId) {
if (mService != null) { if (mService != null) {
try { try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName()); mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Unable to cancel authentication", e); Log.e(TAG, "Unable to cancel authentication", e);
} }
@@ -1024,7 +1034,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
authenticateInternal(operationId, cancel, executor, callback, userId); authenticateInternal(operationId, cancel, executor, callback, userId);
} }
private void authenticateInternal( private long authenticateInternal(
long operationId, long operationId,
@NonNull CancellationSignal cancel, @NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor, @NonNull @CallbackExecutor Executor executor,
@@ -1040,9 +1050,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
try { try {
if (cancel.isCanceled()) { if (cancel.isCanceled()) {
Log.w(TAG, "Authentication already canceled"); Log.w(TAG, "Authentication already canceled");
return; return -1;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener());
} }
mExecutor = executor; mExecutor = executor;
@@ -1065,14 +1073,16 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
promptInfo = mPromptInfo; promptInfo = mPromptInfo;
} }
mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver, final long authId = mService.authenticate(mToken, operationId, userId,
mContext.getOpPackageName(), promptInfo); mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo);
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
return authId;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Remote exception while authenticating", e); Log.e(TAG, "Remote exception while authenticating", e);
mExecutor.execute(() -> callback.onAuthenticationError( mExecutor.execute(() -> callback.onAuthenticationError(
BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
mContext.getString(R.string.biometric_error_hw_unavailable))); mContext.getString(R.string.biometric_error_hw_unavailable)));
return -1;
} }
} }

View File

@@ -41,13 +41,14 @@ interface IAuthService {
// Retrieve the package where BIometricOrompt's UI is implemented // Retrieve the package where BIometricOrompt's UI is implemented
String getUiPackage(); String getUiPackage();
// Requests authentication. The service choose the appropriate biometric to use, and show // Requests authentication. The service chooses the appropriate biometric to use, and shows
// the corresponding BiometricDialog. // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
void authenticate(IBinder token, long sessionId, int userId, // this operation.
long authenticate(IBinder token, long sessionId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
// Cancel authentication for the given sessionId // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics. // TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
// Checks if biometrics can be used. // Checks if biometrics can be used.

View File

@@ -48,13 +48,13 @@ interface IBiometricAuthenticator {
// startPreparedClient(). // startPreparedClient().
void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId, void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, boolean allowBackgroundAuthentication); long requestId, int cookie, boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client. // Starts authentication with the previously prepared client.
void startPreparedClient(int cookie); void startPreparedClient(int cookie);
// Cancels authentication. // Cancels authentication for the given requestId.
void cancelAuthenticationFromService(IBinder token, String opPackageName); void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId);
// Determine if HAL is loaded and ready // Determine if HAL is loaded and ready
boolean isHardwareDetected(String opPackageName); boolean isHardwareDetected(String opPackageName);

View File

@@ -36,13 +36,14 @@ interface IBiometricService {
// Retrieve static sensor properties for all biometric sensors // Retrieve static sensor properties for all biometric sensors
List<SensorPropertiesInternal> getSensorProperties(String opPackageName); List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
// Requests authentication. The service choose the appropriate biometric to use, and show // Requests authentication. The service chooses the appropriate biometric to use, and shows
// the corresponding BiometricDialog. // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
void authenticate(IBinder token, long operationId, int userId, // this operation.
long authenticate(IBinder token, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo); IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
// Cancel authentication for the given session. // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// Checks if biometrics can be used. // Checks if biometrics can be used.
int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators); int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);

View File

@@ -58,7 +58,7 @@ import java.util.List;
public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants { public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
private static final String TAG = "FaceManager"; private static final String TAG = "FaceManager";
private static final boolean DEBUG = true;
private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ENROLL_RESULT = 100;
private static final int MSG_ACQUIRED = 101; private static final int MSG_ACQUIRED = 101;
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
@@ -207,13 +207,9 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
throw new IllegalArgumentException("Must supply an authentication callback"); throw new IllegalArgumentException("Must supply an authentication callback");
} }
if (cancel != null) { if (cancel != null && cancel.isCanceled()) {
if (cancel.isCanceled()) { Slog.w(TAG, "authentication already canceled");
Slog.w(TAG, "authentication already canceled"); return;
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
}
} }
if (mService != null) { if (mService != null) {
@@ -223,17 +219,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mCryptoObject = crypto; mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0; final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate"); Trace.beginSection("FaceManager#authenticate");
mService.authenticate(mToken, operationId, userId, mServiceReceiver, final long authId = mService.authenticate(mToken, operationId, userId,
mContext.getOpPackageName(), isKeyguardBypassEnabled); mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled);
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e); Slog.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) { // Though this may not be a hardware issue, it will cause apps to give up or
// Though this may not be a hardware issue, it will cause apps to give up or // try again later.
// try again later. callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE, getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
0 /* vendorCode */));
}
} finally { } finally {
Trace.endSection(); Trace.endSection();
} }
@@ -255,14 +252,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (cancel.isCanceled()) { if (cancel.isCanceled()) {
Slog.w(TAG, "Detection already cancelled"); Slog.w(TAG, "Detection already cancelled");
return; return;
} else {
cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
} }
mFaceDetectionCallback = callback; mFaceDetectionCallback = callback;
try { try {
mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName()); final long authId = mService.detectFace(
mToken, userId, mServiceReceiver, mContext.getOpPackageName());
cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId));
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e); Slog.w(TAG, "Remote exception when requesting finger detect", e);
} }
@@ -726,23 +723,23 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
} }
} }
private void cancelAuthentication(CryptoObject cryptoObject) { private void cancelAuthentication(long requestId) {
if (mService != null) { if (mService != null) {
try { try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName()); mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
} }
private void cancelFaceDetect() { private void cancelFaceDetect(long requestId) {
if (mService == null) { if (mService == null) {
return; return;
} }
try { try {
mService.cancelFaceDetect(mToken, mContext.getOpPackageName()); mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@@ -1110,22 +1107,30 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
} }
private class OnAuthenticationCancelListener implements OnCancelListener { private class OnAuthenticationCancelListener implements OnCancelListener {
private final CryptoObject mCrypto; private final long mAuthRequestId;
OnAuthenticationCancelListener(CryptoObject crypto) { OnAuthenticationCancelListener(long id) {
mCrypto = crypto; mAuthRequestId = id;
} }
@Override @Override
public void onCancel() { public void onCancel() {
cancelAuthentication(mCrypto); Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId);
cancelAuthentication(mAuthRequestId);
} }
} }
private class OnFaceDetectionCancelListener implements OnCancelListener { private class OnFaceDetectionCancelListener implements OnCancelListener {
private final long mAuthRequestId;
OnFaceDetectionCancelListener(long id) {
mAuthRequestId = id;
}
@Override @Override
public void onCancel() { public void onCancel() {
cancelFaceDetect(); Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId);
cancelFaceDetect(mAuthRequestId);
} }
} }

View File

@@ -44,34 +44,36 @@ interface IFaceService {
// Retrieve static sensor properties for the specified sensor // Retrieve static sensor properties for the specified sensor
FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
// Authenticate the given sessionId with a face // Authenticate with a face. A requestId is returned that can be used to cancel this operation.
void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
String opPackageName, boolean isKeyguardBypassEnabled); String opPackageName, boolean isKeyguardBypassEnabled);
// Uses the face hardware to detect for the presence of a face, without giving details // Uses the face hardware to detect for the presence of a face, without giving details
// about accept/reject/lockout. // about accept/reject/lockout. A requestId is returned that can be used to cancel this
void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName); // operation.
long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
// This method prepares the service to start authenticating, but doesn't start authentication. // 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 // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
// called from BiometricService. The additional uid, pid, userId arguments should be determined // called from BiometricService. The additional uid, pid, userId arguments should be determined
// by BiometricService. To start authentication after the clients are ready, use // by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient(). // startPreparedClient().
void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId, void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
int cookie, boolean allowBackgroundAuthentication); String opPackageName, long requestId, int cookie,
boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client. // Starts authentication with the previously prepared client.
void startPreparedClient(int sensorId, int cookie); void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// Cancel face detection // Cancel face detection for the given requestId.
void cancelFaceDetect(IBinder token, String opPackageName); void cancelFaceDetect(IBinder token, String opPackageName, long requestId);
// Same as above, with extra arguments. // Same as above, with extra arguments.
void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
// Start face enrollment // Start face enrollment
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,

View File

@@ -189,22 +189,30 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
} }
private class OnAuthenticationCancelListener implements OnCancelListener { private class OnAuthenticationCancelListener implements OnCancelListener {
private android.hardware.biometrics.CryptoObject mCrypto; private final long mAuthRequestId;
public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) { OnAuthenticationCancelListener(long id) {
mCrypto = crypto; mAuthRequestId = id;
} }
@Override @Override
public void onCancel() { public void onCancel() {
cancelAuthentication(mCrypto); Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId);
cancelAuthentication(mAuthRequestId);
} }
} }
private class OnFingerprintDetectionCancelListener implements OnCancelListener { private class OnFingerprintDetectionCancelListener implements OnCancelListener {
private final long mAuthRequestId;
OnFingerprintDetectionCancelListener(long id) {
mAuthRequestId = id;
}
@Override @Override
public void onCancel() { public void onCancel() {
cancelFingerprintDetect(); Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId);
cancelFingerprintDetect(mAuthRequestId);
} }
} }
@@ -552,13 +560,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
throw new IllegalArgumentException("Must supply an authentication callback"); throw new IllegalArgumentException("Must supply an authentication callback");
} }
if (cancel != null) { if (cancel != null && cancel.isCanceled()) {
if (cancel.isCanceled()) { Slog.w(TAG, "authentication already canceled");
Slog.w(TAG, "authentication already canceled"); return;
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
}
} }
if (mService != null) { if (mService != null) {
@@ -567,8 +571,11 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mAuthenticationCallback = callback; mAuthenticationCallback = callback;
mCryptoObject = crypto; mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0; final long operationId = crypto != null ? crypto.getOpId() : 0;
mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver, final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
mContext.getOpPackageName()); mServiceReceiver, mContext.getOpPackageName());
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e); Slog.w(TAG, "Remote exception while authenticating: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or try // Though this may not be a hardware issue, it will cause apps to give up or try
@@ -595,15 +602,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
if (cancel.isCanceled()) { if (cancel.isCanceled()) {
Slog.w(TAG, "Detection already cancelled"); Slog.w(TAG, "Detection already cancelled");
return; return;
} else {
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
} }
mFingerprintDetectionCallback = callback; mFingerprintDetectionCallback = callback;
try { try {
mService.detectFingerprint(mToken, userId, mServiceReceiver, final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
mContext.getOpPackageName()); mContext.getOpPackageName());
cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e); Slog.w(TAG, "Remote exception when requesting finger detect", e);
} }
@@ -1320,21 +1326,21 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
} }
} }
private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) { private void cancelAuthentication(long requestId) {
if (mService != null) try { if (mService != null) try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName()); mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
} }
private void cancelFingerprintDetect() { private void cancelFingerprintDetect(long requestId) {
if (mService == null) { if (mService == null) {
return; return;
} }
try { try {
mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName()); mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -48,15 +48,16 @@ interface IFingerprintService {
// Retrieve static sensor properties for the specified sensor // Retrieve static sensor properties for the specified sensor
FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName); FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
// Authenticate the given sessionId with a fingerprint. This is protected by // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC
// USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes // permission. This is effectively deprecated, since it only comes through FingerprintManager
// through FingerprintManager now. // now. A requestId is returned that can be used to cancel this operation.
void authenticate(IBinder token, long operationId, int sensorId, int userId, long authenticate(IBinder token, long operationId, int sensorId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName); IFingerprintServiceReceiver receiver, String opPackageName);
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details // Uses the fingerprint hardware to detect for the presence of a finger, without giving details
// about accept/reject/lockout. // about accept/reject/lockout. A requestId is returned that can be used to cancel this
void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, // operation.
long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
String opPackageName); String opPackageName);
// This method prepares the service to start authenticating, but doesn't start authentication. // This method prepares the service to start authenticating, but doesn't start authentication.
@@ -65,21 +66,21 @@ interface IFingerprintService {
// by BiometricService. To start authentication after the clients are ready, use // by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient(). // startPreparedClient().
void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId, void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
boolean allowBackgroundAuthentication); int cookie, boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client. // Starts authentication with the previously prepared client.
void startPreparedClient(int sensorId, int cookie); void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId // Cancel authentication for the given requestId.
void cancelAuthentication(IBinder token, String opPackageName); void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// Cancel finger detection // Cancel finger detection for the given requestId.
void cancelFingerprintDetect(IBinder token, String opPackageName); void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId);
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
// an additional uid, pid, userid. // an additional uid, pid, userid.
void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName); void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
// Start fingerprint enrollment // Start fingerprint enrollment
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver, void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,

View File

@@ -148,7 +148,7 @@ oneway interface IStatusBar
*/ */
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
String opPackageName, long operationId, int multiSensorConfig); long operationId, String opPackageName, long requestId, int multiSensorConfig);
/** /**
* Used to notify the authentication dialog that a biometric has been authenticated. * Used to notify the authentication dialog that a biometric has been authenticated.
*/ */

View File

@@ -110,7 +110,8 @@ interface IStatusBarService
// Used to show the authentication dialog (Biometrics, Device Credential) // Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId, int multiSensorConfig); int userId, long operationId, String opPackageName, long requestId,
int multiSensorConfig);
// Used to notify the authentication dialog that a biometric has been authenticated // Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated(); void onBiometricAuthenticated();

View File

@@ -126,6 +126,7 @@ public class AuthContainerView extends LinearLayout
boolean mCredentialAllowed; boolean mCredentialAllowed;
boolean mSkipIntro; boolean mSkipIntro;
long mOperationId; long mOperationId;
long mRequestId;
@BiometricMultiSensorMode int mMultiSensorConfig; @BiometricMultiSensorMode int mMultiSensorConfig;
} }
@@ -172,6 +173,12 @@ public class AuthContainerView extends LinearLayout
return this; return this;
} }
/** Unique id for this request. */
public Builder setRequestId(long requestId) {
mConfig.mRequestId = requestId;
return this;
}
/** The multi-sensor mode. */ /** The multi-sensor mode. */
public Builder setMultiSensorConfig(@BiometricMultiSensorMode int multiSensorConfig) { public Builder setMultiSensorConfig(@BiometricMultiSensorMode int multiSensorConfig) {
mConfig.mMultiSensorConfig = multiSensorConfig; mConfig.mMultiSensorConfig = multiSensorConfig;

View File

@@ -501,7 +501,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
@Override @Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId, int userId, long operationId, String opPackageName, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) { @BiometricMultiSensorMode int multiSensorConfig) {
@Authenticators.Types final int authenticators = promptInfo.getAuthenticators(); @Authenticators.Types final int authenticators = promptInfo.getAuthenticators();
@@ -515,6 +515,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
+ ", credentialAllowed: " + credentialAllowed + ", credentialAllowed: " + credentialAllowed
+ ", requireConfirmation: " + requireConfirmation + ", requireConfirmation: " + requireConfirmation
+ ", operationId: " + operationId + ", operationId: " + operationId
+ ", requestId: " + requestId
+ ", multiSensorConfig: " + multiSensorConfig); + ", multiSensorConfig: " + multiSensorConfig);
} }
SomeArgs args = SomeArgs.obtain(); SomeArgs args = SomeArgs.obtain();
@@ -526,6 +527,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
args.argi1 = userId; args.argi1 = userId;
args.arg6 = opPackageName; args.arg6 = opPackageName;
args.arg7 = operationId; args.arg7 = operationId;
args.arg8 = requestId;
args.argi2 = multiSensorConfig; args.argi2 = multiSensorConfig;
boolean skipAnimation = false; boolean skipAnimation = false;
@@ -629,6 +631,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
if (mCurrentDialog == null) { if (mCurrentDialog == null) {
// Could be possible if the caller canceled authentication after credential success // Could be possible if the caller canceled authentication after credential success
// but before the client was notified. // but before the client was notified.
if (DEBUG) Log.d(TAG, "dialog already gone");
return; return;
} }
@@ -683,6 +686,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
final int userId = args.argi1; final int userId = args.argi1;
final String opPackageName = (String) args.arg6; final String opPackageName = (String) args.arg6;
final long operationId = (long) args.arg7; final long operationId = (long) args.arg7;
final long requestId = (long) args.arg8;
final @BiometricMultiSensorMode int multiSensorConfig = args.argi2; final @BiometricMultiSensorMode int multiSensorConfig = args.argi2;
// Create a new dialog but do not replace the current one yet. // Create a new dialog but do not replace the current one yet.
@@ -695,6 +699,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
opPackageName, opPackageName,
skipAnimation, skipAnimation,
operationId, operationId,
requestId,
multiSensorConfig); multiSensorConfig);
if (newDialog == null) { if (newDialog == null) {
@@ -772,7 +777,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation, protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName, int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
boolean skipIntro, long operationId, boolean skipIntro, long operationId, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) { @BiometricMultiSensorMode int multiSensorConfig) {
return new AuthContainerView.Builder(mContext) return new AuthContainerView.Builder(mContext)
.setCallback(this) .setCallback(this)
@@ -782,6 +787,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
.setOpPackageName(opPackageName) .setOpPackageName(opPackageName)
.setSkipIntro(skipIntro) .setSkipIntro(skipIntro)
.setOperationId(operationId) .setOperationId(operationId)
.setRequestId(requestId)
.setMultiSensorConfig(multiSensorConfig) .setMultiSensorConfig(multiSensorConfig)
.build(sensorIds, credentialAllowed, mFpProps, mFaceProps); .build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
} }

View File

@@ -290,8 +290,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
default void showAuthenticationDialog(PromptInfo promptInfo, default void showAuthenticationDialog(PromptInfo promptInfo,
IBiometricSysuiReceiver receiver, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, int[] sensorIds, boolean credentialAllowed,
boolean requireConfirmation, int userId, String opPackageName, boolean requireConfirmation, int userId, long operationId, String opPackageName,
long operationId, @BiometricMultiSensorMode int multiSensorConfig) { long requestId, @BiometricMultiSensorMode int multiSensorConfig) {
} }
/** @see IStatusBar#onBiometricAuthenticated() */ /** @see IStatusBar#onBiometricAuthenticated() */
@@ -843,7 +843,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
@Override @Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId, int userId, long operationId, String opPackageName, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) { @BiometricMultiSensorMode int multiSensorConfig) {
synchronized (mLock) { synchronized (mLock) {
SomeArgs args = SomeArgs.obtain(); SomeArgs args = SomeArgs.obtain();
@@ -855,6 +855,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
args.argi1 = userId; args.argi1 = userId;
args.arg6 = opPackageName; args.arg6 = opPackageName;
args.arg7 = operationId; args.arg7 = operationId;
args.arg8 = requestId;
args.argi2 = multiSensorConfig; args.argi2 = multiSensorConfig;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args) mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget(); .sendToTarget();
@@ -1312,8 +1313,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
(boolean) someArgs.arg4 /* credentialAllowed */, (boolean) someArgs.arg4 /* credentialAllowed */,
(boolean) someArgs.arg5 /* requireConfirmation */, (boolean) someArgs.arg5 /* requireConfirmation */,
someArgs.argi1 /* userId */, someArgs.argi1 /* userId */,
(String) someArgs.arg6 /* opPackageName */,
(long) someArgs.arg7 /* operationId */, (long) someArgs.arg7 /* operationId */,
(String) someArgs.arg6 /* opPackageName */,
(long) someArgs.arg8 /* requestId */,
someArgs.argi2 /* multiSensorConfig */); someArgs.argi2 /* multiSensorConfig */);
} }
someArgs.recycle(); someArgs.recycle();

View File

@@ -565,8 +565,9 @@ public class AuthControllerTest extends SysuiTestCase {
credentialAllowed, credentialAllowed,
true /* requireConfirmation */, true /* requireConfirmation */,
0 /* userId */, 0 /* userId */,
"testPackage",
0 /* operationId */, 0 /* operationId */,
"testPackage",
1 /* requestId */,
BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT); BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT);
} }
@@ -612,7 +613,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Override @Override
protected AuthDialog buildDialog(PromptInfo promptInfo, protected AuthDialog buildDialog(PromptInfo promptInfo,
boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed,
String opPackageName, boolean skipIntro, long operationId, String opPackageName, boolean skipIntro, long operationId, long requestId,
@BiometricManager.BiometricMultiSensorMode int multiSensorConfig) { @BiometricManager.BiometricMultiSensorMode int multiSensorConfig) {
mLastBiometricPromptInfo = promptInfo; mLastBiometricPromptInfo = promptInfo;

View File

@@ -423,17 +423,18 @@ public class CommandQueueTest extends SysuiTestCase {
final boolean credentialAllowed = true; final boolean credentialAllowed = true;
final boolean requireConfirmation = true; final boolean requireConfirmation = true;
final int userId = 10; final int userId = 10;
final String packageName = "test";
final long operationId = 1; final long operationId = 1;
final String packageName = "test";
final long requestId = 10;
final int multiSensorConfig = BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT; final int multiSensorConfig = BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds, mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds,
credentialAllowed, requireConfirmation , userId, packageName, operationId, credentialAllowed, requireConfirmation, userId, operationId, packageName, requestId,
multiSensorConfig); multiSensorConfig);
waitForIdleSync(); waitForIdleSync();
verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds), verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds),
eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName), eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(operationId),
eq(operationId), eq(multiSensorConfig)); eq(packageName), eq(requestId), eq(multiSensorConfig));
} }
@Test @Test

View File

@@ -206,7 +206,7 @@ public class AuthService extends SystemService {
} }
@Override @Override
public void authenticate(IBinder token, long sessionId, int userId, public long authenticate(IBinder token, long sessionId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo)
throws RemoteException { throws RemoteException {
// Only allow internal clients to authenticate with a different userId. // Only allow internal clients to authenticate with a different userId.
@@ -223,18 +223,18 @@ public class AuthService extends SystemService {
if (!checkAppOps(callingUid, opPackageName, "authenticate()")) { if (!checkAppOps(callingUid, opPackageName, "authenticate()")) {
authenticateFastFail("Denied by app ops: " + opPackageName, receiver); authenticateFastFail("Denied by app ops: " + opPackageName, receiver);
return; return -1;
} }
if (token == null || receiver == null || opPackageName == null || promptInfo == null) { if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
authenticateFastFail( authenticateFastFail(
"Unable to authenticate, one or more null arguments", receiver); "Unable to authenticate, one or more null arguments", receiver);
return; return -1;
} }
if (!Utils.isForeground(callingUid, callingPid)) { if (!Utils.isForeground(callingUid, callingPid)) {
authenticateFastFail("Caller is not foreground: " + opPackageName, receiver); authenticateFastFail("Caller is not foreground: " + opPackageName, receiver);
return; return -1;
} }
if (promptInfo.containsTestConfigurations()) { if (promptInfo.containsTestConfigurations()) {
@@ -251,7 +251,7 @@ public class AuthService extends SystemService {
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
mBiometricService.authenticate( return mBiometricService.authenticate(
token, sessionId, userId, receiver, opPackageName, promptInfo); token, sessionId, userId, receiver, opPackageName, promptInfo);
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
@@ -270,7 +270,7 @@ public class AuthService extends SystemService {
} }
@Override @Override
public void cancelAuthentication(IBinder token, String opPackageName) public void cancelAuthentication(IBinder token, String opPackageName, long requestId)
throws RemoteException { throws RemoteException {
checkPermission(); checkPermission();
@@ -281,7 +281,7 @@ public class AuthService extends SystemService {
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
mBiometricService.cancelAuthentication(token, opPackageName); mBiometricService.cancelAuthentication(token, opPackageName, requestId);
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }

View File

@@ -128,6 +128,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
@VisibleForTesting final IBinder mToken; @VisibleForTesting final IBinder mToken;
// Info to be shown on BiometricDialog when all cookies are returned. // Info to be shown on BiometricDialog when all cookies are returned.
@VisibleForTesting final PromptInfo mPromptInfo; @VisibleForTesting final PromptInfo mPromptInfo;
private final long mRequestId;
private final long mOperationId; private final long mOperationId;
private final int mUserId; private final int mUserId;
private final IBiometricSensorReceiver mSensorReceiver; private final IBiometricSensorReceiver mSensorReceiver;
@@ -142,6 +143,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
private @BiometricMultiSensorMode int mMultiSensorMode; private @BiometricMultiSensorMode int mMultiSensorMode;
private @MultiSensorState int mMultiSensorState; private @MultiSensorState int mMultiSensorState;
private int[] mSensors; private int[] mSensors;
// TODO(b/197265902): merge into state
private boolean mCancelled;
// For explicit confirmation, do not send to keystore until the user has confirmed // For explicit confirmation, do not send to keystore until the user has confirmed
// the authentication. // the authentication.
private byte[] mTokenEscrow; private byte[] mTokenEscrow;
@@ -162,6 +165,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
@NonNull ClientDeathReceiver clientDeathReceiver, @NonNull ClientDeathReceiver clientDeathReceiver,
@NonNull PreAuthInfo preAuthInfo, @NonNull PreAuthInfo preAuthInfo,
@NonNull IBinder token, @NonNull IBinder token,
long requestId,
long operationId, long operationId,
int userId, int userId,
@NonNull IBiometricSensorReceiver sensorReceiver, @NonNull IBiometricSensorReceiver sensorReceiver,
@@ -179,6 +183,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
mClientDeathReceiver = clientDeathReceiver; mClientDeathReceiver = clientDeathReceiver;
mPreAuthInfo = preAuthInfo; mPreAuthInfo = preAuthInfo;
mToken = token; mToken = token;
mRequestId = requestId;
mOperationId = operationId; mOperationId = operationId;
mUserId = userId; mUserId = userId;
mSensorReceiver = sensorReceiver; mSensorReceiver = sensorReceiver;
@@ -187,6 +192,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
mPromptInfo = promptInfo; mPromptInfo = promptInfo;
mDebugEnabled = debugEnabled; mDebugEnabled = debugEnabled;
mFingerprintSensorProperties = fingerprintSensorProperties; mFingerprintSensorProperties = fingerprintSensorProperties;
mCancelled = false;
try { try {
mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */); mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */);
@@ -233,7 +239,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id); Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id);
} }
sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId, sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
mUserId, mSensorReceiver, mOpPackageName, cookie, mUserId, mSensorReceiver, mOpPackageName, mRequestId, cookie,
mPromptInfo.isAllowBackgroundAuthentication()); mPromptInfo.isAllowBackgroundAuthentication());
} }
} }
@@ -255,8 +261,9 @@ public final class AuthSession implements IBinder.DeathRecipient {
true /* credentialAllowed */, true /* credentialAllowed */,
false /* requireConfirmation */, false /* requireConfirmation */,
mUserId, mUserId,
mOpPackageName,
mOperationId, mOperationId,
mOpPackageName,
mRequestId,
mMultiSensorMode); mMultiSensorMode);
} else if (!mPreAuthInfo.eligibleSensors.isEmpty()) { } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) {
// Some combination of biometric or biometric|credential is requested // Some combination of biometric or biometric|credential is requested
@@ -270,6 +277,11 @@ public final class AuthSession implements IBinder.DeathRecipient {
} }
void onCookieReceived(int cookie) { void onCookieReceived(int cookie) {
if (mCancelled) {
Slog.w(TAG, "Received cookie but already cancelled (ignoring): " + cookie);
return;
}
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
sensor.goToStateCookieReturnedIfCookieMatches(cookie); sensor.goToStateCookieReturnedIfCookieMatches(cookie);
} }
@@ -301,8 +313,9 @@ public final class AuthSession implements IBinder.DeathRecipient {
mPreAuthInfo.shouldShowCredential(), mPreAuthInfo.shouldShowCredential(),
requireConfirmation, requireConfirmation,
mUserId, mUserId,
mOpPackageName,
mOperationId, mOperationId,
mOpPackageName,
mRequestId,
mMultiSensorMode); mMultiSensorMode);
mState = STATE_AUTH_STARTED; mState = STATE_AUTH_STARTED;
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -369,7 +382,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
final boolean shouldCancel = filter.apply(sensor); final boolean shouldCancel = filter.apply(sensor);
Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel); Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel);
if (shouldCancel) { if (shouldCancel) {
sensor.goToStateCancelling(mToken, mOpPackageName); sensor.goToStateCancelling(mToken, mOpPackageName, mRequestId);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "Unable to cancel authentication"); Slog.e(TAG, "Unable to cancel authentication");
@@ -425,8 +438,9 @@ public final class AuthSession implements IBinder.DeathRecipient {
true /* credentialAllowed */, true /* credentialAllowed */,
false /* requireConfirmation */, false /* requireConfirmation */,
mUserId, mUserId,
mOpPackageName,
mOperationId, mOperationId,
mOpPackageName,
mRequestId,
mMultiSensorMode); mMultiSensorMode);
} else { } else {
mClientReceiver.onError(modality, error, vendorCode); mClientReceiver.onError(modality, error, vendorCode);
@@ -775,6 +789,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
* @return true if this AuthSession is finished, e.g. should be set to null * @return true if this AuthSession is finished, e.g. should be set to null
*/ */
boolean onCancelAuthSession(boolean force) { boolean onCancelAuthSession(boolean force) {
mCancelled = true;
final boolean authStarted = mState == STATE_AUTH_CALLED final boolean authStarted = mState == STATE_AUTH_CALLED
|| mState == STATE_AUTH_STARTED || mState == STATE_AUTH_STARTED
|| mState == STATE_AUTH_STARTED_UI_SHOWING; || mState == STATE_AUTH_STARTED_UI_SHOWING;
@@ -820,6 +836,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
return Utils.isCredentialRequested(mPromptInfo); return Utils.isCredentialRequested(mPromptInfo);
} }
@VisibleForTesting
boolean allCookiesReceived() { boolean allCookiesReceived() {
final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie(); final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie();
Slog.d(TAG, "Remaining cookies: " + remainingCookies); Slog.d(TAG, "Remaining cookies: " + remainingCookies);
@@ -839,6 +856,10 @@ public final class AuthSession implements IBinder.DeathRecipient {
return mState; return mState;
} }
long getRequestId() {
return mRequestId;
}
private int statsModality() { private int statsModality() {
int modality = 0; int modality = 0;
@@ -901,7 +922,9 @@ public final class AuthSession implements IBinder.DeathRecipient {
@Override @Override
public String toString() { public String toString() {
return "State: " + mState return "State: " + mState
+ ", cancelled: " + mCancelled
+ ", isCrypto: " + isCrypto() + ", isCrypto: " + isCrypto()
+ ", PreAuthInfo: " + mPreAuthInfo; + ", PreAuthInfo: " + mPreAuthInfo
+ ", requestId: " + mRequestId;
} }
} }

View File

@@ -108,11 +108,11 @@ public abstract class BiometricSensor {
void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId, void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, boolean allowBackgroundAuthentication) long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException { throws RemoteException {
mCookie = cookie; mCookie = cookie;
impl.prepareForAuthentication(requireConfirmation, token, impl.prepareForAuthentication(requireConfirmation, token,
sessionId, userId, sensorReceiver, opPackageName, mCookie, sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie,
allowBackgroundAuthentication); allowBackgroundAuthentication);
mSensorState = STATE_WAITING_FOR_COOKIE; mSensorState = STATE_WAITING_FOR_COOKIE;
} }
@@ -129,8 +129,9 @@ public abstract class BiometricSensor {
mSensorState = STATE_AUTHENTICATING; mSensorState = STATE_AUTHENTICATING;
} }
void goToStateCancelling(IBinder token, String opPackageName) throws RemoteException { void goToStateCancelling(IBinder token, String opPackageName, long requestId)
impl.cancelAuthenticationFromService(token, opPackageName); throws RemoteException {
impl.cancelAuthenticationFromService(token, opPackageName, requestId);
mSensorState = STATE_CANCELING; mSensorState = STATE_CANCELING;
} }

View File

@@ -83,6 +83,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* System service that arbitrates the modality for BiometricPrompt to use. * System service that arbitrates the modality for BiometricPrompt to use.
@@ -115,6 +116,7 @@ public class BiometricService extends SystemService {
final SettingObserver mSettingObserver; final SettingObserver mSettingObserver;
private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks; private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
private final Random mRandom = new Random(); private final Random mRandom = new Random();
@NonNull private final AtomicLong mRequestCounter;
@VisibleForTesting @VisibleForTesting
IStatusBarService mStatusBarService; IStatusBarService mStatusBarService;
@@ -194,6 +196,7 @@ public class BiometricService extends SystemService {
SomeArgs args = (SomeArgs) msg.obj; SomeArgs args = (SomeArgs) msg.obj;
handleAuthenticate( handleAuthenticate(
(IBinder) args.arg1 /* token */, (IBinder) args.arg1 /* token */,
(long) args.arg6 /* requestId */,
(long) args.arg2 /* operationId */, (long) args.arg2 /* operationId */,
args.argi1 /* userid */, args.argi1 /* userid */,
(IBiometricServiceReceiver) args.arg3 /* receiver */, (IBiometricServiceReceiver) args.arg3 /* receiver */,
@@ -204,7 +207,9 @@ public class BiometricService extends SystemService {
} }
case MSG_CANCEL_AUTHENTICATION: { case MSG_CANCEL_AUTHENTICATION: {
handleCancelAuthentication(); SomeArgs args = (SomeArgs) msg.obj;
handleCancelAuthentication((long) args.arg3 /* requestId */);
args.recycle();
break; break;
} }
@@ -683,13 +688,13 @@ public class BiometricService extends SystemService {
} }
@Override // Binder call @Override // Binder call
public void authenticate(IBinder token, long operationId, int userId, public long authenticate(IBinder token, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
checkInternalPermission(); checkInternalPermission();
if (token == null || receiver == null || opPackageName == null || promptInfo == null) { if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
Slog.e(TAG, "Unable to authenticate, one or more null arguments"); Slog.e(TAG, "Unable to authenticate, one or more null arguments");
return; return -1;
} }
if (!Utils.isValidAuthenticatorConfig(promptInfo)) { if (!Utils.isValidAuthenticatorConfig(promptInfo)) {
@@ -706,6 +711,8 @@ public class BiometricService extends SystemService {
} }
} }
final long requestId = mRequestCounter.incrementAndGet();
SomeArgs args = SomeArgs.obtain(); SomeArgs args = SomeArgs.obtain();
args.arg1 = token; args.arg1 = token;
args.arg2 = operationId; args.arg2 = operationId;
@@ -713,15 +720,23 @@ public class BiometricService extends SystemService {
args.arg3 = receiver; args.arg3 = receiver;
args.arg4 = opPackageName; args.arg4 = opPackageName;
args.arg5 = promptInfo; args.arg5 = promptInfo;
args.arg6 = requestId;
mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget(); mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
return requestId;
} }
@Override // Binder call @Override // Binder call
public void cancelAuthentication(IBinder token, String opPackageName) { public void cancelAuthentication(IBinder token, String opPackageName, long requestId) {
checkInternalPermission(); checkInternalPermission();
mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION).sendToTarget(); SomeArgs args = SomeArgs.obtain();
args.arg1 = token;
args.arg2 = opPackageName;
args.arg3 = requestId;
mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget();
} }
@Override // Binder call @Override // Binder call
@@ -1111,6 +1126,10 @@ public class BiometricService extends SystemService {
return Settings.Secure.getInt(context.getContentResolver(), return Settings.Secure.getInt(context.getContentResolver(),
CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0; CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
} }
public AtomicLong getRequestGenerator() {
return new AtomicLong(0);
}
} }
/** /**
@@ -1136,6 +1155,7 @@ public class BiometricService extends SystemService {
mEnabledOnKeyguardCallbacks = new ArrayList<>(); mEnabledOnKeyguardCallbacks = new ArrayList<>();
mSettingObserver = mInjector.getSettingObserver(context, mHandler, mSettingObserver = mInjector.getSettingObserver(context, mHandler,
mEnabledOnKeyguardCallbacks); mEnabledOnKeyguardCallbacks);
mRequestCounter = mInjector.getRequestGenerator();
// TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't
// need to depend on context. We can remove this code once the advanced logic is enabled // need to depend on context. We can remove this code once the advanced logic is enabled
@@ -1349,7 +1369,7 @@ public class BiometricService extends SystemService {
mCurrentAuthSession.onCookieReceived(cookie); mCurrentAuthSession.onCookieReceived(cookie);
} }
private void handleAuthenticate(IBinder token, long operationId, int userId, private void handleAuthenticate(IBinder token, long requestId, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) { IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
mHandler.post(() -> { mHandler.post(() -> {
try { try {
@@ -1360,7 +1380,8 @@ public class BiometricService extends SystemService {
final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus(); final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();
Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first
+ "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo); + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo
+ " requestId: " + requestId);
if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) { if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) {
// If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but // If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but
@@ -1372,8 +1393,8 @@ public class BiometricService extends SystemService {
promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL); promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL);
} }
authenticateInternal(token, operationId, userId, receiver, opPackageName, authenticateInternal(token, requestId, operationId, userId, receiver,
promptInfo, preAuthInfo); opPackageName, promptInfo, preAuthInfo);
} else { } else {
receiver.onError(preAuthStatus.first /* modality */, receiver.onError(preAuthStatus.first /* modality */,
preAuthStatus.second /* errorCode */, preAuthStatus.second /* errorCode */,
@@ -1394,7 +1415,7 @@ public class BiometricService extends SystemService {
* Note that this path is NOT invoked when the BiometricPrompt "Try again" button is pressed. * Note that this path is NOT invoked when the BiometricPrompt "Try again" button is pressed.
* In that case, see {@link #handleOnTryAgainPressed()}. * In that case, see {@link #handleOnTryAgainPressed()}.
*/ */
private void authenticateInternal(IBinder token, long operationId, int userId, private void authenticateInternal(IBinder token, long requestId, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo, IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo,
PreAuthInfo preAuthInfo) { PreAuthInfo preAuthInfo) {
Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo); Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo);
@@ -1412,9 +1433,9 @@ public class BiometricService extends SystemService {
final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId); final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId);
mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver, mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver,
mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId, mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, requestId,
mBiometricSensorReceiver, receiver, opPackageName, promptInfo, debugEnabled, operationId, userId, mBiometricSensorReceiver, receiver, opPackageName, promptInfo,
mInjector.getFingerprintSensorProperties(getContext())); debugEnabled, mInjector.getFingerprintSensorProperties(getContext()));
try { try {
mCurrentAuthSession.goToInitialState(); mCurrentAuthSession.goToInitialState();
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -1422,11 +1443,21 @@ public class BiometricService extends SystemService {
} }
} }
private void handleCancelAuthentication() { private void handleCancelAuthentication(long requestId) {
if (mCurrentAuthSession == null) { if (mCurrentAuthSession == null) {
Slog.e(TAG, "handleCancelAuthentication: AuthSession is null"); Slog.e(TAG, "handleCancelAuthentication: AuthSession is null");
return; return;
} }
if (mCurrentAuthSession.getRequestId() != requestId) {
// TODO: actually cancel the operation
// This can happen if the operation has been queued, but is cancelled before
// it reaches the head of the scheduler. Consider it a programming error for now
// and ignore it.
Slog.e(TAG, "handleCancelAuthentication: AuthSession mismatch current requestId: "
+ mCurrentAuthSession.getRequestId() + " cancel for: " + requestId
+ " (ignoring cancellation)");
return;
}
final boolean finished = mCurrentAuthSession.onCancelAuthSession(false /* force */); final boolean finished = mCurrentAuthSession.onCancelAuthSession(false /* force */);
if (finished) { if (finished) {

View File

@@ -101,6 +101,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor
private final int mSensorId; // sensorId as configured by the framework private final int mSensorId; // sensorId as configured by the framework
@Nullable private IBinder mToken; @Nullable private IBinder mToken;
private long mRequestId;
@Nullable private ClientMonitorCallbackConverter mListener; @Nullable private ClientMonitorCallbackConverter mListener;
// Currently only used for authentication client. The cookie generated by BiometricService // Currently only used for authentication client. The cookie generated by BiometricService
// is never 0. // is never 0.
@@ -154,6 +155,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor
mSequentialId = sCount++; mSequentialId = sCount++;
mContext = context; mContext = context;
mToken = token; mToken = token;
mRequestId = -1;
mListener = listener; mListener = listener;
mTargetUserId = userId; mTargetUserId = userId;
mOwner = owner; mOwner = owner;
@@ -258,6 +260,29 @@ public abstract class BaseClientMonitor extends LoggableMonitor
return mSensorId; return mSensorId;
} }
/** Unique request id. */
public final long getRequestId() {
return mRequestId;
}
/** If a unique id has been set via {@link #setRequestId(long)} */
public final boolean hasRequestId() {
return mRequestId > 0;
}
/**
* A unique identifier used to tie this operation to a request (i.e an API invocation).
*
* Subclasses should not call this method if this operation does not have a direct
* correspondence to a request and {@link #hasRequestId()} will return false.
*/
protected final void setRequestId(long id) {
if (id <= 0) {
throw new IllegalArgumentException("request id must be positive");
}
mRequestId = id;
}
@VisibleForTesting @VisibleForTesting
public Callback getCallback() { public Callback getCallback() {
return mCallback; return mCallback;
@@ -270,6 +295,7 @@ public abstract class BaseClientMonitor extends LoggableMonitor
+ ", proto=" + getProtoEnum() + ", proto=" + getProtoEnum()
+ ", owner=" + getOwnerString() + ", owner=" + getOwnerString()
+ ", cookie=" + getCookie() + ", cookie=" + getCookie()
+ ", requestId=" + getRequestId()
+ ", userId=" + getTargetUserId() + "}"; + ", userId=" + getTargetUserId() + "}";
} }
} }

View File

@@ -643,22 +643,18 @@ public class BiometricScheduler {
/** /**
* Requests to cancel authentication or detection. * Requests to cancel authentication or detection.
* @param token from the caller, should match the token passed in when requesting authentication * @param token from the caller, should match the token passed in when requesting authentication
* @param requestId the id returned when requesting authentication
*/ */
public void cancelAuthenticationOrDetection(IBinder token) { public void cancelAuthenticationOrDetection(IBinder token, long requestId) {
if (mCurrentOperation == null) { Slog.d(getTag(), "cancelAuthenticationOrDetection, requestId: " + requestId
Slog.e(getTag(), "Unable to cancel authentication, null operation"); + " current: " + mCurrentOperation
return; + " stack size: " + mPendingOperations.size());
}
final boolean isCorrectClient = isAuthenticationOrDetectionOperation(mCurrentOperation);
final boolean tokenMatches = mCurrentOperation.mClientMonitor.getToken() == token;
Slog.d(getTag(), "cancelAuthenticationOrDetection, isCorrectClient: " + isCorrectClient if (mCurrentOperation != null
+ ", tokenMatches: " + tokenMatches); && canCancelAuthOperation(mCurrentOperation, token, requestId)) {
if (isCorrectClient && tokenMatches) {
Slog.d(getTag(), "Cancelling: " + mCurrentOperation); Slog.d(getTag(), "Cancelling: " + mCurrentOperation);
cancelInternal(mCurrentOperation); cancelInternal(mCurrentOperation);
} else if (!isCorrectClient) { } else {
// Look through the current queue for all authentication clients for the specified // Look through the current queue for all authentication clients for the specified
// token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking // token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking
// all of them, instead of just the first one, since the API surface currently doesn't // all of them, instead of just the first one, since the API surface currently doesn't
@@ -666,8 +662,7 @@ public class BiometricScheduler {
// process. However, this generally does not happen anyway, and would be a class of // process. However, this generally does not happen anyway, and would be a class of
// bugs on its own. // bugs on its own.
for (Operation operation : mPendingOperations) { for (Operation operation : mPendingOperations) {
if (isAuthenticationOrDetectionOperation(operation) if (canCancelAuthOperation(operation, token, requestId)) {
&& operation.mClientMonitor.getToken() == token) {
Slog.d(getTag(), "Marking " + operation Slog.d(getTag(), "Marking " + operation
+ " as STATE_WAITING_IN_QUEUE_CANCELING"); + " as STATE_WAITING_IN_QUEUE_CANCELING");
operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING; operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING;
@@ -676,10 +671,26 @@ public class BiometricScheduler {
} }
} }
private boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) { private static boolean canCancelAuthOperation(Operation operation, IBinder token,
final boolean isAuthentication = operation.mClientMonitor long requestId) {
instanceof AuthenticationConsumer; // TODO: restrict callers that can cancel without requestId (negative value)?
final boolean isDetection = operation.mClientMonitor instanceof DetectionConsumer; return isAuthenticationOrDetectionOperation(operation)
&& operation.mClientMonitor.getToken() == token
&& isMatchingRequestId(operation, requestId);
}
// By default, monitors are not associated with a request id to retain the original
// behavior (i.e. if no requestId is explicitly set then assume it matches)
private static boolean isMatchingRequestId(Operation operation, long requestId) {
return !operation.mClientMonitor.hasRequestId()
|| operation.mClientMonitor.getRequestId() == requestId;
}
private static boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) {
final boolean isAuthentication =
operation.mClientMonitor instanceof AuthenticationConsumer;
final boolean isDetection =
operation.mClientMonitor instanceof DetectionConsumer;
return isAuthentication || isDetection; return isAuthentication || isDetection;
} }

View File

@@ -61,10 +61,11 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
@Override @Override
public void prepareForAuthentication(boolean requireConfirmation, IBinder token, public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long operationId, int userId, IBiometricSensorReceiver sensorReceiver, long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, boolean allowBackgroundAuthentication) String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException { throws RemoteException {
mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId, mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
userId, sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication); userId, sensorReceiver, opPackageName, requestId, cookie,
allowBackgroundAuthentication);
} }
@Override @Override
@@ -73,9 +74,9 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
} }
@Override @Override
public void cancelAuthenticationFromService(IBinder token, String opPackageName) public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
throws RemoteException { throws RemoteException {
mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName); mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, requestId);
} }
@Override @Override

View File

@@ -250,7 +250,7 @@ public class FaceService extends SystemService {
} }
@Override // Binder call @Override // Binder call
public void authenticate(final IBinder token, final long operationId, int userId, public long authenticate(final IBinder token, final long operationId, int userId,
final IFaceServiceReceiver receiver, final String opPackageName, final IFaceServiceReceiver receiver, final String opPackageName,
boolean isKeyguardBypassEnabled) { boolean isKeyguardBypassEnabled) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
@@ -270,38 +270,38 @@ public class FaceService extends SystemService {
final Pair<Integer, ServiceProvider> provider = getSingleProvider(); final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) { if (provider == null) {
Slog.w(TAG, "Null provider for authenticate"); Slog.w(TAG, "Null provider for authenticate");
return; return -1;
} }
provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */, 0 /* cookie */,
new ClientMonitorCallbackConverter(receiver), opPackageName, restricted, new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
statsClient, isKeyguard, isKeyguardBypassEnabled); statsClient, isKeyguard, isKeyguardBypassEnabled);
} }
@Override // Binder call @Override // Binder call
public void detectFace(final IBinder token, final int userId, public long detectFace(final IBinder token, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) { final IFaceServiceReceiver receiver, final String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) { if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName); Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName);
return; return -1;
} }
if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
// If this happens, something in KeyguardUpdateMonitor is wrong. This should only // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
// ever be invoked when the user is encrypted or lockdown. // ever be invoked when the user is encrypted or lockdown.
Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown"); Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown");
return; return -1;
} }
final Pair<Integer, ServiceProvider> provider = getSingleProvider(); final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) { if (provider == null) {
Slog.w(TAG, "Null provider for detectFace"); Slog.w(TAG, "Null provider for detectFace");
return; return -1;
} }
provider.second.scheduleFaceDetect(provider.first, token, userId, return provider.second.scheduleFaceDetect(provider.first, token, userId,
new ClientMonitorCallbackConverter(receiver), opPackageName, new ClientMonitorCallbackConverter(receiver), opPackageName,
BiometricsProtoEnums.CLIENT_KEYGUARD); BiometricsProtoEnums.CLIENT_KEYGUARD);
} }
@@ -309,8 +309,8 @@ public class FaceService extends SystemService {
@Override // Binder call @Override // Binder call
public void prepareForAuthentication(int sensorId, boolean requireConfirmation, public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
IBinder token, long operationId, int userId, IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie, IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
boolean allowBackgroundAuthentication) { int cookie, boolean allowBackgroundAuthentication) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId); final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -322,9 +322,9 @@ public class FaceService extends SystemService {
final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients
final boolean restricted = true; // BiometricPrompt is always restricted final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication, restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
isKeyguardBypassEnabled); allowBackgroundAuthentication, isKeyguardBypassEnabled);
} }
@Override // Binder call @Override // Binder call
@@ -341,7 +341,8 @@ public class FaceService extends SystemService {
} }
@Override // Binder call @Override // Binder call
public void cancelAuthentication(final IBinder token, final String opPackageName) { public void cancelAuthentication(final IBinder token, final String opPackageName,
final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final Pair<Integer, ServiceProvider> provider = getSingleProvider(); final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -350,11 +351,12 @@ public class FaceService extends SystemService {
return; return;
} }
provider.second.cancelAuthentication(provider.first, token); provider.second.cancelAuthentication(provider.first, token, requestId);
} }
@Override // Binder call @Override // Binder call
public void cancelFaceDetect(final IBinder token, final String opPackageName) { public void cancelFaceDetect(final IBinder token, final String opPackageName,
final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) { if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "cancelFaceDetect called from non-sysui package: " Slog.w(TAG, "cancelFaceDetect called from non-sysui package: "
@@ -368,12 +370,12 @@ public class FaceService extends SystemService {
return; return;
} }
provider.second.cancelFaceDetect(provider.first, token); provider.second.cancelFaceDetect(provider.first, token, requestId);
} }
@Override // Binder call @Override // Binder call
public void cancelAuthenticationFromService(int sensorId, final IBinder token, public void cancelAuthenticationFromService(int sensorId, final IBinder token,
final String opPackageName) { final String opPackageName, final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId); final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -382,7 +384,7 @@ public class FaceService extends SystemService {
return; return;
} }
provider.cancelAuthentication(sensorId, token); provider.cancelAuthentication(sensorId, token, requestId);
} }
@Override // Binder call @Override // Binder call

View File

@@ -101,18 +101,23 @@ public interface ServiceProvider {
void cancelEnrollment(int sensorId, @NonNull IBinder token); void cancelEnrollment(int sensorId, @NonNull IBinder token);
void scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId, long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient); int statsClient);
void cancelFaceDetect(int sensorId, @NonNull IBinder token); void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId);
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled); boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
void cancelAuthentication(int sensorId, @NonNull IBinder token); void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId);
void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId, void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
@NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName); @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName);

View File

@@ -65,7 +65,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
@FaceManager.FaceAcquired private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN; @FaceManager.FaceAcquired private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN;
FaceAuthenticationClient(@NonNull Context context, FaceAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, @NonNull LazyDaemon<ISession> lazyDaemon,
@NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats, boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
@@ -76,6 +77,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */, lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
isKeyguardBypassEnabled); isKeyguardBypassEnabled);
setRequestId(requestId);
mUsageStats = usageStats; mUsageStats = usageStats;
mLockoutCache = lockoutCache; mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class); mNotificationManager = context.getSystemService(NotificationManager.class);

View File

@@ -43,11 +43,13 @@ public class FaceDetectClient extends AcquisitionClient<ISession> implements Det
@Nullable private ICancellationSignal mCancellationSignal; @Nullable private ICancellationSignal mCancellationSignal;
public FaceDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, public FaceDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) { @NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE,
BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric; mIsStrongBiometric = isStrongBiometric;
} }

View File

@@ -65,6 +65,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Provider for a single instance of the {@link IFace} HAL. * Provider for a single instance of the {@link IFace} HAL.
@@ -83,6 +84,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull private final UsageStats mUsageStats; @NonNull private final UsageStats mUsageStats;
@NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener; @NonNull private final BiometricTaskStackListener mTaskStackListener;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
@Nullable private IFace mDaemon; @Nullable private IFace mDaemon;
@@ -110,8 +113,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
&& !client.isAlreadyDone()) { && !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication, top: " Slog.e(getTag(), "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client); + topPackage + " currentClient: " + client);
mSensors.valueAt(i).getScheduler() mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
.cancelAuthenticationOrDetection(client.getToken()); client.getToken(), client.getRequestId());
} }
} }
} }
@@ -356,34 +359,39 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
} }
@Override @Override
public void scheduleFaceDetect(int sensorId, @NonNull IBinder token, public long scheduleFaceDetect(int sensorId, @NonNull IBinder token,
int userId, @NonNull ClientMonitorCallbackConverter callback, int userId, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, int statsClient) { @NonNull String opPackageName, int statsClient) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> { mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceDetectClient client = new FaceDetectClient(mContext, final FaceDetectClient client = new FaceDetectClient(mContext,
mSensors.get(sensorId).getLazySession(), token, callback, userId, opPackageName, mSensors.get(sensorId).getLazySession(),
token, id, callback, userId, opPackageName,
sensorId, isStrongBiometric, statsClient); sensorId, isStrongBiometric, statsClient);
scheduleForSensor(sensorId, client); scheduleForSensor(sensorId, client);
}); });
return id;
} }
@Override @Override
public void cancelFaceDetect(int sensorId, @NonNull IBinder token) { public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler() mHandler.post(() -> mSensors.get(sensorId).getScheduler()
.cancelAuthenticationOrDetection(token)); .cancelAuthenticationOrDetection(token, requestId));
} }
@Override @Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> { mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient( final FaceAuthenticationClient client = new FaceAuthenticationClient(
mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId, mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
operationId, restricted, opPackageName, cookie, userId, operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache(), mUsageStats, mSensors.get(sensorId).getLockoutCache(),
allowBackgroundAuthentication, isKeyguardBypassEnabled); allowBackgroundAuthentication, isKeyguardBypassEnabled);
@@ -392,9 +400,23 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
} }
@Override @Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) { public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
opPackageName, id, restricted, statsClient,
allowBackgroundAuthentication, isKeyguardBypassEnabled);
return id;
}
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler() mHandler.post(() -> mSensors.get(sensorId).getScheduler()
.cancelAuthenticationOrDetection(token)); .cancelAuthenticationOrDetection(token, requestId));
} }
@Override @Override

View File

@@ -87,6 +87,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or its extended * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or its extended
@@ -115,6 +116,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@NonNull private final Map<Integer, Long> mAuthenticatorIds; @NonNull private final Map<Integer, Long> mAuthenticatorIds;
@Nullable private IBiometricsFace mDaemon; @Nullable private IBiometricsFace mDaemon;
@NonNull private final HalResultController mHalResultController; @NonNull private final HalResultController mHalResultController;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
private int mCurrentUserId = UserHandle.USER_NULL; private int mCurrentUserId = UserHandle.USER_NULL;
private final int mSensorId; private final int mSensorId;
private final List<Long> mGeneratedChallengeCount = new ArrayList<>(); private final List<Long> mGeneratedChallengeCount = new ArrayList<>();
@@ -605,7 +608,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
} }
@Override @Override
public void scheduleFaceDetect(int sensorId, @NonNull IBinder token, public long scheduleFaceDetect(int sensorId, @NonNull IBinder token,
int userId, @NonNull ClientMonitorCallbackConverter callback, int userId, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, int statsClient) { @NonNull String opPackageName, int statsClient) {
throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you"
@@ -613,7 +616,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
} }
@Override @Override
public void cancelFaceDetect(int sensorId, @NonNull IBinder token) { public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) {
throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you"
+ "forget to check the supportsFaceDetection flag?"); + "forget to check the supportsFaceDetection flag?");
} }
@@ -621,26 +624,38 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
@Override @Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) { boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> { mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId); scheduleUpdateActiveUserWithoutHandler(userId);
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext, final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName, mLazyDaemon, token, requestId, receiver, userId, operationId, restricted,
cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric, opPackageName, cookie, false /* requireConfirmation */, mSensorId,
statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication, isStrongBiometric, statsClient, mLockoutTracker, mUsageStats,
isKeyguardBypassEnabled); allowBackgroundAuthentication, isKeyguardBypassEnabled);
mScheduler.scheduleClientMonitor(client); mScheduler.scheduleClientMonitor(client);
}); });
} }
@Override @Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) { public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
mHandler.post(() -> { int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
mScheduler.cancelAuthenticationOrDetection(token); @NonNull String opPackageName, boolean restricted, int statsClient,
}); boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, receiver,
opPackageName, id, restricted, statsClient,
allowBackgroundAuthentication, isKeyguardBypassEnabled);
return id;
}
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId));
} }
@Override @Override

View File

@@ -57,7 +57,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
private int mLastAcquire; private int mLastAcquire;
FaceAuthenticationClient(@NonNull Context context, FaceAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
@NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker, boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
@@ -68,6 +69,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */, lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
isKeyguardBypassEnabled); isKeyguardBypassEnabled);
setRequestId(requestId);
mUsageStats = usageStats; mUsageStats = usageStats;
final Resources resources = getContext().getResources(); final Resources resources = getContext().getResources();

View File

@@ -61,10 +61,10 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
@Override @Override
public void prepareForAuthentication(boolean requireConfirmation, IBinder token, public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long operationId, int userId, IBiometricSensorReceiver sensorReceiver, long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, boolean allowBackgroundAuthentication) String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException { throws RemoteException {
mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId, mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId,
sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication); sensorReceiver, opPackageName, requestId, cookie, allowBackgroundAuthentication);
} }
@Override @Override
@@ -73,9 +73,10 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
} }
@Override @Override
public void cancelAuthenticationFromService(IBinder token, String opPackageName) public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
throws RemoteException { throws RemoteException {
mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName); mFingerprintService.cancelAuthenticationFromService(
mSensorId, token, opPackageName, requestId);
} }
@Override @Override

View File

@@ -245,7 +245,7 @@ public class FingerprintService extends SystemService {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Override // Binder call @Override // Binder call
public void authenticate(final IBinder token, final long operationId, public long authenticate(final IBinder token, final long operationId,
final int sensorId, final int userId, final IFingerprintServiceReceiver receiver, final int sensorId, final int userId, final IFingerprintServiceReceiver receiver,
final String opPackageName) { final String opPackageName) {
final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid();
@@ -255,7 +255,7 @@ public class FingerprintService extends SystemService {
if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid, if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid,
callingPid, callingUserId)) { callingPid, callingUserId)) {
Slog.w(TAG, "Authenticate rejecting package: " + opPackageName); Slog.w(TAG, "Authenticate rejecting package: " + opPackageName);
return; return -1;
} }
// Keyguard check must be done on the caller's binder identity, since it also checks // Keyguard check must be done on the caller's binder identity, since it also checks
@@ -270,7 +270,7 @@ public class FingerprintService extends SystemService {
// SafetyNet for b/79776455 // SafetyNet for b/79776455
EventLog.writeEvent(0x534e4554, "79776455"); EventLog.writeEvent(0x534e4554, "79776455");
Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown"); Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown");
return; return -1;
} }
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
@@ -290,7 +290,7 @@ public class FingerprintService extends SystemService {
} }
if (provider == null) { if (provider == null) {
Slog.w(TAG, "Null provider for authenticate"); Slog.w(TAG, "Null provider for authenticate");
return; return -1;
} }
final FingerprintSensorPropertiesInternal sensorProps = final FingerprintSensorPropertiesInternal sensorProps =
@@ -299,18 +299,17 @@ public class FingerprintService extends SystemService {
&& sensorProps != null && sensorProps.isAnyUdfpsType()) { && sensorProps != null && sensorProps.isAnyUdfpsType()) {
identity = Binder.clearCallingIdentity(); identity = Binder.clearCallingIdentity();
try { try {
authenticateWithPrompt(operationId, sensorProps, userId, receiver); return authenticateWithPrompt(operationId, sensorProps, userId, receiver);
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
} else {
provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
restricted, statsClient, isKeyguard, mFingerprintStateCallback);
} }
return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
restricted, statsClient, isKeyguard, mFingerprintStateCallback);
} }
private void authenticateWithPrompt( private long authenticateWithPrompt(
final long operationId, final long operationId,
@NonNull final FingerprintSensorPropertiesInternal props, @NonNull final FingerprintSensorPropertiesInternal props,
final int userId, final int userId,
@@ -387,33 +386,33 @@ public class FingerprintService extends SystemService {
} }
}; };
biometricPrompt.authenticateUserForOperation( return biometricPrompt.authenticateUserForOperation(
new CancellationSignal(), executor, promptCallback, userId, operationId); new CancellationSignal(), executor, promptCallback, userId, operationId);
} }
@Override @Override
public void detectFingerprint(final IBinder token, final int userId, public long detectFingerprint(final IBinder token, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) { final IFingerprintServiceReceiver receiver, final String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) { if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName); Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName);
return; return -1;
} }
if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) { if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
// If this happens, something in KeyguardUpdateMonitor is wrong. This should only // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
// ever be invoked when the user is encrypted or lockdown. // ever be invoked when the user is encrypted or lockdown.
Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown"); Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
return; return -1;
} }
final Pair<Integer, ServiceProvider> provider = getSingleProvider(); final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) { if (provider == null) {
Slog.w(TAG, "Null provider for detectFingerprint"); Slog.w(TAG, "Null provider for detectFingerprint");
return; return -1;
} }
provider.second.scheduleFingerDetect(provider.first, token, userId, return provider.second.scheduleFingerDetect(provider.first, token, userId,
new ClientMonitorCallbackConverter(receiver), opPackageName, new ClientMonitorCallbackConverter(receiver), opPackageName,
BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback); BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback);
} }
@@ -421,7 +420,7 @@ public class FingerprintService extends SystemService {
@Override // Binder call @Override // Binder call
public void prepareForAuthentication(int sensorId, IBinder token, long operationId, public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName, int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, boolean allowBackgroundAuthentication) { long requestId, int cookie, boolean allowBackgroundAuthentication) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
final ServiceProvider provider = getProviderForSensor(sensorId); final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -432,9 +431,9 @@ public class FingerprintService extends SystemService {
final boolean restricted = true; // BiometricPrompt is always restricted final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie, provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication, restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
mFingerprintStateCallback); allowBackgroundAuthentication, mFingerprintStateCallback);
} }
@Override // Binder call @Override // Binder call
@@ -452,7 +451,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call @Override // Binder call
public void cancelAuthentication(final IBinder token, final String opPackageName) { public void cancelAuthentication(final IBinder token, final String opPackageName,
long requestId) {
final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid(); final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId(); final int callingUserId = UserHandle.getCallingUserId();
@@ -469,11 +469,12 @@ public class FingerprintService extends SystemService {
return; return;
} }
provider.second.cancelAuthentication(provider.first, token); provider.second.cancelAuthentication(provider.first, token, requestId);
} }
@Override // Binder call @Override // Binder call
public void cancelFingerprintDetect(final IBinder token, final String opPackageName) { public void cancelFingerprintDetect(final IBinder token, final String opPackageName,
final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) { if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: " Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: "
@@ -489,12 +490,12 @@ public class FingerprintService extends SystemService {
return; return;
} }
provider.second.cancelAuthentication(provider.first, token); provider.second.cancelAuthentication(provider.first, token, requestId);
} }
@Override // Binder call @Override // Binder call
public void cancelAuthenticationFromService(final int sensorId, final IBinder token, public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
final String opPackageName) { final String opPackageName, final long requestId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
@@ -506,7 +507,7 @@ public class FingerprintService extends SystemService {
return; return;
} }
provider.cancelAuthentication(sensorId, token); provider.cancelAuthentication(sensorId, token, requestId);
} }
@Override // Binder call @Override // Binder call

View File

@@ -95,12 +95,18 @@ public interface ServiceProvider {
void cancelEnrollment(int sensorId, @NonNull IBinder token); void cancelEnrollment(int sensorId, @NonNull IBinder token);
void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient, int statsClient,
@NonNull FingerprintStateCallback fingerprintStateCallback); @NonNull FingerprintStateCallback fingerprintStateCallback);
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback);
long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication,
@@ -108,7 +114,7 @@ public interface ServiceProvider {
void startPreparedClient(int sensorId, int cookie); void startPreparedClient(int sensorId, int cookie);
void cancelAuthentication(int sensorId, @NonNull IBinder token); void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId);
void scheduleRemove(int sensorId, @NonNull IBinder token, void scheduleRemove(int sensorId, @NonNull IBinder token,
@NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId, @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,

View File

@@ -61,7 +61,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
private boolean mIsPointerDown; private boolean mIsPointerDown;
FingerprintAuthenticationClient(@NonNull Context context, FingerprintAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, @NonNull LazyDaemon<ISession> lazyDaemon,
@NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
int sensorId, boolean isStrongBiometric, int statsClient, int sensorId, boolean isStrongBiometric, int statsClient,
@@ -74,6 +75,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */, lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
false /* isKeyguardBypassEnabled */); false /* isKeyguardBypassEnabled */);
setRequestId(requestId);
mLockoutCache = lockoutCache; mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController; mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps; mSensorProps = sensorProps;

View File

@@ -47,13 +47,15 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> implements Det
@Nullable private ICancellationSignal mCancellationSignal; @Nullable private ICancellationSignal mCancellationSignal;
FingerprintDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon, FingerprintDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int sensorId, @NonNull String owner, int sensorId,
@Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric, @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric,
int statsClient) { int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric; mIsStrongBiometric = isStrongBiometric;
mUdfpsOverlayController = udfpsOverlayController; mUdfpsOverlayController = udfpsOverlayController;
} }

View File

@@ -71,6 +71,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Provider for a single instance of the {@link IFingerprint} HAL. * Provider for a single instance of the {@link IFingerprint} HAL.
@@ -88,6 +89,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull private final ActivityTaskManager mActivityTaskManager; @NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener; @NonNull private final BiometricTaskStackListener mTaskStackListener;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
@Nullable private IFingerprint mDaemon; @Nullable private IFingerprint mDaemon;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController; @Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@@ -118,8 +121,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
&& !client.isAlreadyDone()) { && !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication, top: " Slog.e(getTag(), "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client); + topPackage + " currentClient: " + client);
mSensors.valueAt(i).getScheduler() mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
.cancelAuthenticationOrDetection(client.getToken()); client.getToken(), client.getRequestId());
} }
} }
} }
@@ -369,31 +372,35 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
} }
@Override @Override
public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName, @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient, int statsClient,
@NonNull FingerprintStateCallback fingerprintStateCallback) { @NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> { mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext, final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
mSensors.get(sensorId).getLazySession(), token, callback, userId, mSensors.get(sensorId).getLazySession(), token, id, callback, userId,
opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric, opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric,
statsClient); statsClient);
scheduleForSensor(sensorId, client, fingerprintStateCallback); scheduleForSensor(sensorId, client, fingerprintStateCallback);
}); });
return id;
} }
@Override @Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback, int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback) { @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> { mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId, mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
operationId, restricted, opPackageName, cookie, userId, operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
mUdfpsOverlayController, allowBackgroundAuthentication, mUdfpsOverlayController, allowBackgroundAuthentication,
@@ -402,15 +409,30 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}); });
} }
@Override
public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
opPackageName, id, restricted, statsClient, allowBackgroundAuthentication,
fingerprintStateCallback);
return id;
}
@Override @Override
public void startPreparedClient(int sensorId, int cookie) { public void startPreparedClient(int sensorId, int cookie) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie)); mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie));
} }
@Override @Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) { public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler() mHandler.post(() -> mSensors.get(sensorId).getScheduler()
.cancelAuthenticationOrDetection(token)); .cancelAuthenticationOrDetection(token, requestId));
} }
@Override @Override

View File

@@ -88,6 +88,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or * Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or
@@ -115,6 +116,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull private final HalResultController mHalResultController; @NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController; @Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ISidefpsController mSidefpsController; @Nullable private ISidefpsController mSidefpsController;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
private int mCurrentUserId = UserHandle.USER_NULL; private int mCurrentUserId = UserHandle.USER_NULL;
private final boolean mIsUdfps; private final boolean mIsUdfps;
private final int mSensorId; private final int mSensorId;
@@ -142,7 +145,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
&& !client.isAlreadyDone()) { && !client.isAlreadyDone()) {
Slog.e(TAG, "Stopping background authentication, top: " Slog.e(TAG, "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client); + topPackage + " currentClient: " + client);
mScheduler.cancelAuthenticationOrDetection(client.getToken()); mScheduler.cancelAuthenticationOrDetection(
client.getToken(), client.getRequestId());
} }
} }
}); });
@@ -591,26 +595,30 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
} }
@Override @Override
public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId, public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName, @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
int statsClient, int statsClient,
@NonNull FingerprintStateCallback fingerprintStateCallback) { @NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> { mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId); scheduleUpdateActiveUserWithoutHandler(userId);
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext, final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
mLazyDaemon, token, listener, userId, opPackageName, mLazyDaemon, token, id, listener, userId, opPackageName,
mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric, mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric,
statsClient); statsClient);
mScheduler.scheduleClientMonitor(client, fingerprintStateCallback); mScheduler.scheduleClientMonitor(client, fingerprintStateCallback);
}); });
return id;
} }
@Override @Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener, int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, boolean restricted, int statsClient, @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback) { @NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> { mHandler.post(() -> {
@@ -618,8 +626,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId); final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
mContext, mLazyDaemon, token, listener, userId, operationId, restricted, mContext, mLazyDaemon, token, requestId, listener, userId, operationId,
opPackageName, cookie, false /* requireConfirmation */, restricted, opPackageName, cookie, false /* requireConfirmation */,
mSensorProperties.sensorId, isStrongBiometric, statsClient, mSensorProperties.sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mLockoutTracker, mUdfpsOverlayController, mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
allowBackgroundAuthentication, mSensorProperties); allowBackgroundAuthentication, mSensorProperties);
@@ -627,15 +635,30 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}); });
} }
@Override
public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
final long id = mRequestCounter.incrementAndGet();
scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener,
opPackageName, id, restricted, statsClient, allowBackgroundAuthentication,
fingerprintStateCallback);
return id;
}
@Override @Override
public void startPreparedClient(int sensorId, int cookie) { public void startPreparedClient(int sensorId, int cookie) {
mHandler.post(() -> mScheduler.startPreparedClient(cookie)); mHandler.post(() -> mScheduler.startPreparedClient(cookie));
} }
@Override @Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) { public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
Slog.d(TAG, "cancelAuthentication, sensorId: " + sensorId); Slog.d(TAG, "cancelAuthentication, sensorId: " + sensorId);
mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token)); mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId));
} }
@Override @Override

View File

@@ -59,7 +59,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
private boolean mIsPointerDown; private boolean mIsPointerDown;
FingerprintAuthenticationClient(@NonNull Context context, FingerprintAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token, @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon,
@NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation, boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
int sensorId, boolean isStrongBiometric, int statsClient, int sensorId, boolean isStrongBiometric, int statsClient,
@@ -73,6 +74,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener, BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */, lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
false /* isKeyguardBypassEnabled */); false /* isKeyguardBypassEnabled */);
setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker; mLockoutFrameworkImpl = lockoutTracker;
mUdfpsOverlayController = udfpsOverlayController; mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps; mSensorProps = sensorProps;

View File

@@ -52,13 +52,15 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
private boolean mIsPointerDown; private boolean mIsPointerDown;
public FingerprintDetectClient(@NonNull Context context, public FingerprintDetectClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token, @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon,
@NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController, int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController,
boolean isStrongBiometric, int statsClient) { boolean isStrongBiometric, int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT, true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient); BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
setRequestId(requestId);
mUdfpsOverlayController = udfpsOverlayController; mUdfpsOverlayController = udfpsOverlayController;
mIsStrongBiometric = isStrongBiometric; mIsStrongBiometric = isStrongBiometric;
} }

View File

@@ -59,7 +59,7 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
@Override @Override
public void prepareForAuthentication(boolean requireConfirmation, IBinder token, public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long sessionId, int userId, IBiometricSensorReceiver sensorReceiver, long sessionId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, boolean allowBackgroundAuthentication) String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException { throws RemoteException {
} }
@@ -68,7 +68,7 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
} }
@Override @Override
public void cancelAuthenticationFromService(IBinder token, String opPackageName) public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
throws RemoteException { throws RemoteException {
} }

View File

@@ -783,13 +783,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override @Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver, public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId, int userId, long operationId, String opPackageName, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) { @BiometricMultiSensorMode int multiSensorConfig) {
enforceBiometricDialog(); enforceBiometricDialog();
if (mBar != null) { if (mBar != null) {
try { try {
mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed, mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed,
requireConfirmation, userId, opPackageName, operationId, multiSensorConfig); requireConfirmation, userId, operationId, opPackageName, requestId,
multiSensorConfig);
} catch (RemoteException ex) { } catch (RemoteException ex) {
} }
} }

View File

@@ -74,6 +74,7 @@ import java.util.function.Consumer;
public class AuthSessionTest { public class AuthSessionTest {
private static final String TEST_PACKAGE = "test_package"; private static final String TEST_PACKAGE = "test_package";
private static final long TEST_REQUEST_ID = 22;
@Mock private Context mContext; @Mock private Context mContext;
@Mock private ITrustManager mTrustManager; @Mock private ITrustManager mTrustManager;
@@ -112,6 +113,7 @@ public class AuthSessionTest {
final AuthSession session = createAuthSession(mSensors, final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */, false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG, Authenticators.BIOMETRIC_STRONG,
TEST_REQUEST_ID,
0 /* operationId */, 0 /* operationId */,
0 /* userId */); 0 /* userId */);
@@ -133,6 +135,7 @@ public class AuthSessionTest {
final AuthSession session = createAuthSession(mSensors, final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */, false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG, Authenticators.BIOMETRIC_STRONG,
TEST_REQUEST_ID,
operationId, operationId,
userId); userId);
assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
@@ -153,6 +156,7 @@ public class AuthSessionTest {
eq(userId), eq(userId),
eq(mSensorReceiver), eq(mSensorReceiver),
eq(TEST_PACKAGE), eq(TEST_PACKAGE),
eq(TEST_REQUEST_ID),
eq(sensor.getCookie()), eq(sensor.getCookie()),
anyBoolean() /* allowBackgroundAuthentication */); anyBoolean() /* allowBackgroundAuthentication */);
} }
@@ -184,6 +188,33 @@ public class AuthSessionTest {
} }
} }
@Test
public void testCancelReducesAppetiteForCookies() throws Exception {
setupFace(0 /* id */, false /* confirmationAlwaysRequired */,
mock(IBiometricAuthenticator.class));
setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG,
TEST_REQUEST_ID,
44 /* operationId */,
2 /* userId */);
session.goToInitialState();
for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
}
session.onCancelAuthSession(false /* force */);
for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
session.onCookieReceived(sensor.getCookie());
assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState());
}
}
@Test @Test
public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes() public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes()
throws Exception { throws Exception {
@@ -212,6 +243,7 @@ public class AuthSessionTest {
final AuthSession session = createAuthSession(mSensors, final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */, false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG, Authenticators.BIOMETRIC_STRONG,
TEST_REQUEST_ID,
operationId, operationId,
userId); userId);
assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size()); assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
@@ -238,7 +270,7 @@ public class AuthSessionTest {
// fingerprint sensor does not start even if all cookies are received // fingerprint sensor does not start even if all cookies are received
assertEquals(STATE_AUTH_STARTED, session.getState()); assertEquals(STATE_AUTH_STARTED, session.getState());
verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(), verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(),
anyBoolean(), anyBoolean(), anyInt(), any(), anyLong(), anyInt()); anyBoolean(), anyBoolean(), anyInt(), anyLong(), any(), anyLong(), anyInt());
// Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started. // Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started.
session.onDialogAnimatedIn(); session.onDialogAnimatedIn();
@@ -277,6 +309,7 @@ public class AuthSessionTest {
final AuthSession session = createAuthSession(mSensors, final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */, false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG, Authenticators.BIOMETRIC_STRONG,
TEST_REQUEST_ID,
0 /* operationId */, 0 /* operationId */,
0 /* userId */); 0 /* userId */);
@@ -285,7 +318,8 @@ public class AuthSessionTest {
sessionConsumer.accept(session); sessionConsumer.accept(session);
verify(faceAuthenticator).cancelAuthenticationFromService(eq(mToken), eq(TEST_PACKAGE)); verify(faceAuthenticator).cancelAuthenticationFromService(
eq(mToken), eq(TEST_PACKAGE), eq(TEST_REQUEST_ID));
} }
private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId, private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId,
@@ -302,14 +336,14 @@ public class AuthSessionTest {
private AuthSession createAuthSession(List<BiometricSensor> sensors, private AuthSession createAuthSession(List<BiometricSensor> sensors,
boolean checkDevicePolicyManager, @Authenticators.Types int authenticators, boolean checkDevicePolicyManager, @Authenticators.Types int authenticators,
long operationId, int userId) throws RemoteException { long requestId, long operationId, int userId) throws RemoteException {
final PromptInfo promptInfo = createPromptInfo(authenticators); final PromptInfo promptInfo = createPromptInfo(authenticators);
final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo, final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo,
checkDevicePolicyManager); checkDevicePolicyManager);
return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore, return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore,
mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId, mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId, operationId, userId,
mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
false /* debugEnabled */, mFingerprintSensorProps); false /* debugEnabled */, mFingerprintSensorProps);
} }

View File

@@ -85,6 +85,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.Random; import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
@Presubmit @Presubmit
@SmallTest @SmallTest
@@ -93,6 +94,7 @@ public class BiometricServiceTest {
private static final String TAG = "BiometricServiceTest"; private static final String TAG = "BiometricServiceTest";
private static final String TEST_PACKAGE_NAME = "test_package"; private static final String TEST_PACKAGE_NAME = "test_package";
private static final long TEST_REQUEST_ID = 44;
private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable"; private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable";
private static final String ERROR_NOT_RECOGNIZED = "not_recognized"; private static final String ERROR_NOT_RECOGNIZED = "not_recognized";
@@ -151,6 +153,7 @@ public class BiometricServiceTest {
.thenReturn(mock(BiometricStrengthController.class)); .thenReturn(mock(BiometricStrengthController.class));
when(mInjector.getTrustManager()).thenReturn(mTrustManager); when(mInjector.getTrustManager()).thenReturn(mTrustManager);
when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager); when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager);
when(mInjector.getRequestGenerator()).thenReturn(new AtomicLong(TEST_REQUEST_ID - 1));
when(mResources.getString(R.string.biometric_error_hw_unavailable)) when(mResources.getString(R.string.biometric_error_hw_unavailable))
.thenReturn(ERROR_HW_UNAVAILABLE); .thenReturn(ERROR_HW_UNAVAILABLE);
@@ -215,8 +218,7 @@ public class BiometricServiceTest {
mBiometricService.mCurrentAuthSession.getState()); mBiometricService.mCurrentAuthSession.getState());
verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl) verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl)
.cancelAuthenticationFromService(any(), .cancelAuthenticationFromService(any(), any(), anyLong());
any());
// Simulate ERROR_CANCELED received from HAL // Simulate ERROR_CANCELED received from HAL
mBiometricService.mBiometricSensorReceiver.onError( mBiometricService.mBiometricSensorReceiver.onError(
@@ -272,8 +274,9 @@ public class BiometricServiceTest {
eq(true) /* credentialAllowed */, eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
} }
@@ -357,8 +360,9 @@ public class BiometricServiceTest {
eq(false) /* credentialAllowed */, eq(false) /* credentialAllowed */,
eq(false) /* requireConfirmation */, eq(false) /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
} }
@@ -467,6 +471,7 @@ public class BiometricServiceTest {
anyInt() /* userId */, anyInt() /* userId */,
any(IBiometricSensorReceiver.class), any(IBiometricSensorReceiver.class),
anyString() /* opPackageName */, anyString() /* opPackageName */,
eq(TEST_REQUEST_ID),
cookieCaptor.capture() /* cookie */, cookieCaptor.capture() /* cookie */,
anyBoolean() /* allowBackgroundAuthentication */); anyBoolean() /* allowBackgroundAuthentication */);
@@ -488,8 +493,9 @@ public class BiometricServiceTest {
eq(false) /* credentialAllowed */, eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Hardware authenticated // Hardware authenticated
@@ -543,8 +549,9 @@ public class BiometricServiceTest {
eq(true) /* credentialAllowed */, eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
} }
@@ -705,8 +712,9 @@ public class BiometricServiceTest {
anyBoolean() /* credentialAllowed */, anyBoolean() /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
anyString(), anyString(),
anyLong() /* sessionId */, anyLong() /* requestId */,
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
} }
@@ -805,8 +813,9 @@ public class BiometricServiceTest {
eq(true) /* credentialAllowed */, eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
} }
@@ -885,8 +894,9 @@ public class BiometricServiceTest {
eq(true) /* credentialAllowed */, eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
} }
@@ -1030,8 +1040,7 @@ public class BiometricServiceTest {
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
eq(0 /* vendorCode */)); eq(0 /* vendorCode */));
verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService( verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService(
any(), any(), any(), anyLong());
any());
assertNull(mBiometricService.mCurrentAuthSession); assertNull(mBiometricService.mCurrentAuthSession);
} }
@@ -1051,7 +1060,7 @@ public class BiometricServiceTest {
waitForIdle(); waitForIdle();
verify(mBiometricService.mSensors.get(0).impl) verify(mBiometricService.mSensors.get(0).impl)
.cancelAuthenticationFromService(any(), any()); .cancelAuthenticationFromService(any(), any(), anyLong());
} }
@Test @Test
@@ -1071,7 +1080,7 @@ public class BiometricServiceTest {
waitForIdle(); waitForIdle();
verify(mBiometricService.mSensors.get(0).impl) verify(mBiometricService.mSensors.get(0).impl)
.cancelAuthenticationFromService(any(), any()); .cancelAuthenticationFromService(any(), any(), anyLong());
} }
@Test @Test
@@ -1088,7 +1097,7 @@ public class BiometricServiceTest {
waitForIdle(); waitForIdle();
verify(mBiometricService.mSensors.get(0).impl) verify(mBiometricService.mSensors.get(0).impl)
.cancelAuthenticationFromService(any(), any()); .cancelAuthenticationFromService(any(), any(), anyLong());
verify(mReceiver1).onError( verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_FACE), eq(BiometricAuthenticator.TYPE_FACE),
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
@@ -1126,7 +1135,7 @@ public class BiometricServiceTest {
false /* requireConfirmation */, null /* authenticators */); false /* requireConfirmation */, null /* authenticators */);
mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken, mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken,
TEST_PACKAGE_NAME); TEST_PACKAGE_NAME, TEST_REQUEST_ID);
waitForIdle(); waitForIdle();
// Pretend that the HAL has responded to cancel with ERROR_CANCELED // Pretend that the HAL has responded to cancel with ERROR_CANCELED
@@ -1353,8 +1362,8 @@ public class BiometricServiceTest {
int authenticators = Authenticators.BIOMETRIC_STRONG; int authenticators = Authenticators.BIOMETRIC_STRONG;
assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED, assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
invokeCanAuthenticate(mBiometricService, authenticators)); invokeCanAuthenticate(mBiometricService, authenticators));
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */, long requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
authenticators); false /* requireConfirmation */, authenticators);
waitForIdle(); waitForIdle();
verify(mReceiver1).onError( verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_FINGERPRINT), eq(BiometricAuthenticator.TYPE_FINGERPRINT),
@@ -1366,7 +1375,7 @@ public class BiometricServiceTest {
authenticators = Authenticators.BIOMETRIC_WEAK; authenticators = Authenticators.BIOMETRIC_WEAK;
assertEquals(BiometricManager.BIOMETRIC_SUCCESS, assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators)); invokeCanAuthenticate(mBiometricService, authenticators));
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, false /* requireConfirmation */,
authenticators); authenticators);
waitForIdle(); waitForIdle();
@@ -1377,8 +1386,9 @@ public class BiometricServiceTest {
eq(false) /* credentialAllowed */, eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(requestId),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Requesting strong and credential, when credential is setup // Requesting strong and credential, when credential is setup
@@ -1387,7 +1397,7 @@ public class BiometricServiceTest {
when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true); when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
assertEquals(BiometricManager.BIOMETRIC_SUCCESS, assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators)); invokeCanAuthenticate(mBiometricService, authenticators));
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, false /* requireConfirmation */,
authenticators); authenticators);
waitForIdle(); waitForIdle();
@@ -1399,8 +1409,9 @@ public class BiometricServiceTest {
eq(true) /* credentialAllowed */, eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(requestId),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Un-downgrading the authenticator allows successful strong auth // Un-downgrading the authenticator allows successful strong auth
@@ -1414,7 +1425,7 @@ public class BiometricServiceTest {
authenticators = Authenticators.BIOMETRIC_STRONG; authenticators = Authenticators.BIOMETRIC_STRONG;
assertEquals(BiometricManager.BIOMETRIC_SUCCESS, assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators)); invokeCanAuthenticate(mBiometricService, authenticators));
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, authenticators); false /* requireConfirmation */, authenticators);
waitForIdle(); waitForIdle();
verify(mBiometricService.mStatusBarService).showAuthenticationDialog( verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
@@ -1424,8 +1435,9 @@ public class BiometricServiceTest {
eq(false) /* credentialAllowed */, eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */, anyBoolean() /* requireConfirmation */,
anyInt() /* userId */, anyInt() /* userId */,
anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME), eq(TEST_PACKAGE_NAME),
anyLong() /* sessionId */, eq(requestId),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT)); eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
} }
@@ -1617,11 +1629,12 @@ public class BiometricServiceTest {
mBiometricService.mStatusBarService = mock(IStatusBarService.class); mBiometricService.mStatusBarService = mock(IStatusBarService.class);
} }
private void invokeAuthenticateAndStart(IBiometricService.Stub service, private long invokeAuthenticateAndStart(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, boolean requireConfirmation, IBiometricServiceReceiver receiver, boolean requireConfirmation,
Integer authenticators) throws Exception { Integer authenticators) throws Exception {
// Request auth, creates a pending session // Request auth, creates a pending session
invokeAuthenticate(service, receiver, requireConfirmation, authenticators); final long requestId = invokeAuthenticate(
service, receiver, requireConfirmation, authenticators);
waitForIdle(); waitForIdle();
startPendingAuthSession(mBiometricService); startPendingAuthSession(mBiometricService);
@@ -1629,6 +1642,8 @@ public class BiometricServiceTest {
assertNotNull(mBiometricService.mCurrentAuthSession); assertNotNull(mBiometricService.mCurrentAuthSession);
assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
return requestId;
} }
private static void startPendingAuthSession(BiometricService service) throws Exception { private static void startPendingAuthSession(BiometricService service) throws Exception {
@@ -1644,10 +1659,10 @@ public class BiometricServiceTest {
service.mImpl.onReadyForAuthentication(cookie); service.mImpl.onReadyForAuthentication(cookie);
} }
private static void invokeAuthenticate(IBiometricService.Stub service, private static long invokeAuthenticate(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, boolean requireConfirmation, IBiometricServiceReceiver receiver, boolean requireConfirmation,
Integer authenticators) throws Exception { Integer authenticators) throws Exception {
service.authenticate( return service.authenticate(
new Binder() /* token */, new Binder() /* token */,
0 /* operationId */, 0 /* operationId */,
0 /* userId */, 0 /* userId */,
@@ -1657,9 +1672,9 @@ public class BiometricServiceTest {
false /* checkDevicePolicy */)); false /* checkDevicePolicy */));
} }
private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service, private static long invokeAuthenticateForWorkApp(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, Integer authenticators) throws Exception { IBiometricServiceReceiver receiver, Integer authenticators) throws Exception {
service.authenticate( return service.authenticate(
new Binder() /* token */, new Binder() /* token */,
0 /* operationId */, 0 /* operationId */,
0 /* userId */, 0 /* userId */,

View File

@@ -40,6 +40,7 @@ import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext; import android.testing.TestableContext;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -193,7 +194,7 @@ public class BiometricSchedulerTest {
// Request it to be canceled. The operation can be canceled immediately, and the scheduler // Request it to be canceled. The operation can be canceled immediately, and the scheduler
// should go back to idle, since in this case the framework has not even requested the HAL // should go back to idle, since in this case the framework has not even requested the HAL
// to authenticate yet. // to authenticate yet.
mScheduler.cancelAuthenticationOrDetection(mToken); mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */);
assertNull(mScheduler.mCurrentOperation); assertNull(mScheduler.mCurrentOperation);
} }
@@ -303,7 +304,7 @@ public class BiometricSchedulerTest {
mScheduler.mPendingOperations.getFirst().mState); mScheduler.mPendingOperations.getFirst().mState);
// Request cancel before the authentication client has started // Request cancel before the authentication client has started
mScheduler.cancelAuthenticationOrDetection(mToken); mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */);
waitForIdle(); waitForIdle();
assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING, assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING,
mScheduler.mPendingOperations.getFirst().mState); mScheduler.mPendingOperations.getFirst().mState);
@@ -317,6 +318,107 @@ public class BiometricSchedulerTest {
assertNull(mScheduler.getCurrentClient()); assertNull(mScheduler.getCurrentClient());
} }
@Test
public void testCancels_whenAuthRequestIdNotSet() {
testCancelsWhenRequestId(null /* requestId */, 2, true /* started */);
}
@Test
public void testCancels_whenAuthRequestIdNotSet_notStarted() {
testCancelsWhenRequestId(null /* requestId */, 2, false /* started */);
}
@Test
public void testCancels_whenAuthRequestIdMatches() {
testCancelsWhenRequestId(200L, 200, true /* started */);
}
@Test
public void testCancels_whenAuthRequestIdMatches_noStarted() {
testCancelsWhenRequestId(200L, 200, false /* started */);
}
@Test
public void testDoesNotCancel_whenAuthRequestIdMismatched() {
testCancelsWhenRequestId(10L, 20, true /* started */);
}
@Test
public void testDoesNotCancel_whenAuthRequestIdMismatched_notStarted() {
testCancelsWhenRequestId(10L, 20, false /* started */);
}
private void testCancelsWhenRequestId(@Nullable Long requestId, long cancelRequestId,
boolean started) {
final boolean matches = requestId == null || requestId == cancelRequestId;
final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class);
final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
final TestAuthenticationClient client = new TestAuthenticationClient(
mContext, lazyDaemon, mToken, callback);
if (requestId != null) {
client.setRequestId(requestId);
}
mScheduler.scheduleClientMonitor(client);
if (started) {
mScheduler.startPreparedClient(client.getCookie());
}
waitForIdle();
mScheduler.cancelAuthenticationOrDetection(mToken, cancelRequestId);
waitForIdle();
assertEquals(matches && started ? 1 : 0, client.mNumCancels);
if (matches) {
if (started) {
assertEquals(Operation.STATE_STARTED_CANCELING,
mScheduler.mCurrentOperation.mState);
}
} else {
if (started) {
assertEquals(Operation.STATE_STARTED,
mScheduler.mCurrentOperation.mState);
} else {
assertEquals(Operation.STATE_WAITING_FOR_COOKIE,
mScheduler.mCurrentOperation.mState);
}
}
}
@Test
public void testCancelsPending_whenAuthRequestIdsSet() {
final long requestId1 = 10;
final long requestId2 = 20;
final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class);
final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
final TestAuthenticationClient client1 = new TestAuthenticationClient(
mContext, lazyDaemon, mToken, callback);
client1.setRequestId(requestId1);
final TestAuthenticationClient client2 = new TestAuthenticationClient(
mContext, lazyDaemon, mToken, callback);
client2.setRequestId(requestId2);
mScheduler.scheduleClientMonitor(client1);
mScheduler.scheduleClientMonitor(client2);
mScheduler.startPreparedClient(client1.getCookie());
waitForIdle();
mScheduler.cancelAuthenticationOrDetection(mToken, 9999);
waitForIdle();
assertEquals(Operation.STATE_STARTED,
mScheduler.mCurrentOperation.mState);
assertEquals(Operation.STATE_WAITING_IN_QUEUE,
mScheduler.mPendingOperations.getFirst().mState);
mScheduler.cancelAuthenticationOrDetection(mToken, requestId2);
waitForIdle();
assertEquals(Operation.STATE_STARTED,
mScheduler.mCurrentOperation.mState);
assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING,
mScheduler.mPendingOperations.getFirst().mState);
}
@Test @Test
public void testInterruptPrecedingClients_whenExpected() { public void testInterruptPrecedingClients_whenExpected() {
final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class, final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class,
@@ -377,12 +479,10 @@ public class BiometricSchedulerTest {
@Override @Override
protected void stopHalOperation() { protected void stopHalOperation() {
} }
@Override @Override
protected void startHalOperation() { protected void startHalOperation() {
} }
@Override @Override
@@ -397,6 +497,7 @@ public class BiometricSchedulerTest {
} }
private static class TestAuthenticationClient extends AuthenticationClient<Object> { private static class TestAuthenticationClient extends AuthenticationClient<Object> {
int mNumCancels = 0;
public TestAuthenticationClient(@NonNull Context context, public TestAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token, @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token,
@@ -428,6 +529,11 @@ public class BiometricSchedulerTest {
public boolean wasUserDetected() { public boolean wasUserDetected() {
return false; return false;
} }
public void cancel() {
mNumCancels++;
super.cancel();
}
} }
private static class TestClientMonitor2 extends TestClientMonitor { private static class TestClientMonitor2 extends TestClientMonitor {