summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/face/FaceManager.java111
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl4
-rw-r--r--core/java/android/hardware/face/IFaceServiceReceiver.aidl1
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java97
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl4
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java53
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java43
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java56
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java53
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java95
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java56
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java54
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java59
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java2
17 files changed, 584 insertions, 130 deletions
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index b64ce999ff82..9876de11a2bb 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -41,7 +41,6 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
-import android.util.Log;
import android.util.Slog;
import android.view.Surface;
@@ -49,6 +48,9 @@ import com.android.internal.R;
import com.android.internal.os.SomeArgs;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
/**
* A class that coordinates access to the face authentication hardware.
@@ -67,6 +69,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
private static final int MSG_REMOVED = 105;
private static final int MSG_GET_FEATURE_COMPLETED = 106;
private static final int MSG_SET_FEATURE_COMPLETED = 107;
+ private static final int MSG_CHALLENGE_GENERATED = 108;
private IFaceService mService;
private final Context mContext;
@@ -76,6 +79,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
private RemovalCallback mRemovalCallback;
private SetFeatureCallback mSetFeatureCallback;
private GetFeatureCallback mGetFeatureCallback;
+ private GenerateChallengeCallback mGenerateChallengeCallback;
private CryptoObject mCryptoObject;
private Face mRemovalFace;
private Handler mHandler;
@@ -126,6 +130,17 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
args.arg2 = value;
mHandler.obtainMessage(MSG_GET_FEATURE_COMPLETED, args).sendToTarget();
}
+
+ @Override
+ public void onChallengeGenerated(long challenge) {
+ if (mGenerateChallengeCallback instanceof InternalGenerateChallengeCallback) {
+ // Perform this on system_server thread, since the application's thread is
+ // blocked waiting for the result
+ mGenerateChallengeCallback.onGenerateChallengeResult(challenge);
+ } else {
+ mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, challenge).sendToTarget();
+ }
+ }
};
/**
@@ -207,7 +222,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (cancel != null) {
if (cancel.isCanceled()) {
- Log.w(TAG, "authentication already canceled");
+ Slog.w(TAG, "authentication already canceled");
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
@@ -224,7 +239,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mService.authenticate(mToken, operationId, userId, mServiceReceiver,
flags, mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.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
// try again later.
@@ -278,7 +293,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (cancel != null) {
if (cancel.isCanceled()) {
- Log.w(TAG, "enrollment already canceled");
+ Slog.w(TAG, "enrollment already canceled");
return;
} else {
cancel.setOnCancelListener(new OnEnrollCancelListener());
@@ -292,7 +307,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mService.enroll(userId, mToken, token, mServiceReceiver,
mContext.getOpPackageName(), disabledFeatures, surface);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in enroll: ", e);
+ Slog.w(TAG, "Remote exception in enroll: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or
// try again later.
callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
@@ -330,7 +345,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
if (cancel != null) {
if (cancel.isCanceled()) {
- Log.w(TAG, "enrollRemotely is already canceled.");
+ Slog.w(TAG, "enrollRemotely is already canceled.");
return;
} else {
cancel.setOnCancelListener(new OnEnrollCancelListener());
@@ -344,7 +359,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mService.enrollRemotely(userId, mToken, token, mServiceReceiver,
mContext.getOpPackageName(), disabledFeatures);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in enrollRemotely: ", e);
+ Slog.w(TAG, "Remote exception in enrollRemotely: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or
// try again later.
callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
@@ -357,22 +372,56 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
- * Requests an auth token to tie sensitive operations to the confirmation of
- * existing device credentials (e.g. pin/pattern/password).
+ * Same as {@link #generateChallenge(GenerateChallengeCallback)}, except blocks until the
+ * TEE/hardware operation is complete.
+ * @return challenge generated in the TEE/hardware
+ * @hide
+ */
+ @RequiresPermission(MANAGE_BIOMETRIC)
+ public long generateChallengeBlocking() {
+ final AtomicReference<Long> result = new AtomicReference<>();
+ final CountDownLatch latch = new CountDownLatch(1);
+ final GenerateChallengeCallback callback = new InternalGenerateChallengeCallback() {
+ @Override
+ public void onGenerateChallengeResult(long challenge) {
+ result.set(challenge);
+ latch.countDown();
+ }
+ };
+
+ generateChallenge(callback);
+
+ try {
+ latch.await(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Interrupted while generatingChallenge", e);
+ e.printStackTrace();
+ }
+ return result.get();
+ }
+
+ /**
+ * Generates a unique random challenge in the TEE. A typical use case is to have it wrapped in a
+ * HardwareAuthenticationToken, minted by Gatekeeper upon PIN/Pattern/Password verification.
+ * The HardwareAuthenticationToken can then be sent to the biometric HAL together with a
+ * request to perform sensitive operation(s) (for example enroll or setFeature), represented
+ * by the challenge. Doing this ensures that a the sensitive operation cannot be performed
+ * unless the user has entered confirmed PIN/Pattern/Password.
+ *
+ * @see com.android.server.locksettings.LockSettingsService
*
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public long generateChallenge() {
- long result = 0;
+ public void generateChallenge(GenerateChallengeCallback callback) {
if (mService != null) {
try {
- result = mService.generateChallenge(mToken);
+ mGenerateChallengeCallback = callback;
+ mService.generateChallenge(mToken, mServiceReceiver, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- return result;
}
/**
@@ -381,16 +430,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public int revokeChallenge() {
- int result = 0;
+ public void revokeChallenge() {
if (mService != null) {
try {
- result = mService.revokeChallenge(mToken);
+ mService.revokeChallenge(mToken, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- return result;
}
/**
@@ -458,7 +505,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mService.remove(mToken, face.getBiometricId(), userId, mServiceReceiver,
mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in remove: ", e);
+ Slog.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
callback.onRemovalError(face, FACE_ERROR_HW_UNAVAILABLE,
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
@@ -546,7 +593,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
throw e.rethrowFromSystemServer();
}
} else {
- Log.w(TAG, "isFaceHardwareDetected(): Service not connected!");
+ Slog.w(TAG, "isFaceHardwareDetected(): Service not connected!");
}
return false;
}
@@ -586,7 +633,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
throw e.rethrowFromSystemServer();
}
} else {
- Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
+ Slog.w(TAG, "addLockoutResetCallback(): Service not connected!");
}
}
@@ -967,6 +1014,16 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
public abstract void onCompleted(boolean success, int feature, boolean value);
}
+ /**
+ * @hide
+ */
+ public abstract static class GenerateChallengeCallback {
+ public abstract void onGenerateChallengeResult(long challenge);
+ }
+
+ private abstract static class InternalGenerateChallengeCallback
+ extends GenerateChallengeCallback {}
+
private class OnEnrollCancelListener implements OnCancelListener {
@Override
public void onCancel() {
@@ -1030,8 +1087,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
(boolean) args.arg2 /* value */);
args.recycle();
break;
+ case MSG_CHALLENGE_GENERATED:
+ sendChallengeGenerated((long) msg.obj /* challenge */);
+ break;
default:
- Log.w(TAG, "Unknown message: " + msg.what);
+ Slog.w(TAG, "Unknown message: " + msg.what);
}
Trace.endSection();
}
@@ -1051,12 +1111,19 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mGetFeatureCallback.onCompleted(success, feature, value);
}
+ private void sendChallengeGenerated(long challenge) {
+ if (mGenerateChallengeCallback == null) {
+ return;
+ }
+ mGenerateChallengeCallback.onGenerateChallengeResult(challenge);
+ }
+
private void sendRemovedResult(Face face, int remaining) {
if (mRemovalCallback == null) {
return;
}
if (face == null) {
- Log.e(TAG, "Received MSG_REMOVED, but face is null");
+ Slog.e(TAG, "Received MSG_REMOVED, but face is null");
return;
}
mRemovalCallback.onRemovalSucceeded(face, remaining);
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index f5ac047885ca..8dbaf2115fe5 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -72,10 +72,10 @@ interface IFaceService {
boolean isHardwareDetected(String opPackageName);
// Get a pre-enrollment authentication token
- long generateChallenge(IBinder token);
+ void generateChallenge(IBinder token, IFaceServiceReceiver receiver, String opPackageName);
// Finish an enrollment sequence and invalidate the authentication token
- int revokeChallenge(IBinder token);
+ void revokeChallenge(IBinder token, String opPackageName);
// Determine if a user has at least one enrolled face
boolean hasEnrolledFaces(int userId, String opPackageName);
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
index ff3f6f39586e..844657e7453f 100644
--- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -30,4 +30,5 @@ oneway interface IFaceServiceReceiver {
void onRemoved(in Face face, int remaining);
void onFeatureSet(boolean success, int feature);
void onFeatureGet(boolean success, int feature, boolean value);
+ void onChallengeGenerated(long challenge);
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 713c169352d0..4787984cdf41 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -50,7 +50,10 @@ import android.view.Surface;
import java.security.Signature;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -75,6 +78,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private static final int MSG_AUTHENTICATION_FAILED = 103;
private static final int MSG_ERROR = 104;
private static final int MSG_REMOVED = 105;
+ private static final int MSG_CHALLENGE_GENERATED = 106;
private IFingerprintService mService;
private Context mContext;
@@ -82,6 +86,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private AuthenticationCallback mAuthenticationCallback;
private EnrollmentCallback mEnrollmentCallback;
private RemovalCallback mRemovalCallback;
+ private GenerateChallengeCallback mGenerateChallengeCallback;
private CryptoObject mCryptoObject;
private Fingerprint mRemovalFingerprint;
private Handler mHandler;
@@ -346,6 +351,16 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
};
/**
+ * @hide
+ */
+ public abstract static class GenerateChallengeCallback {
+ public abstract void onChallengeGenerated(long challenge);
+ }
+
+ private abstract static class InternalGenerateChallengeCallback
+ extends GenerateChallengeCallback {}
+
+ /**
* Request authentication of a crypto object. This call warms up the fingerprint hardware
* and starts scanning for a fingerprint. It terminates when
* {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
@@ -514,19 +529,56 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
/**
- * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
- * existing device credentials (e.g. pin/pattern/password).
+ * Same as {@link #generateChallenge(GenerateChallengeCallback)}, except blocks until the
+ * TEE/hardware operation is complete.
+ * @return challenge generated in the TEE/hardware
+ * @hide
+ */
+ @RequiresPermission(MANAGE_FINGERPRINT)
+ public long generateChallengeBlocking() {
+ final AtomicReference<Long> result = new AtomicReference<>();
+ final CountDownLatch latch = new CountDownLatch(1);
+ final GenerateChallengeCallback callback = new InternalGenerateChallengeCallback() {
+ @Override
+ public void onChallengeGenerated(long challenge) {
+ result.set(challenge);
+ latch.countDown();
+ }
+ };
+
+ generateChallenge(callback);
+
+ try {
+ latch.await(1, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Interrupted while generatingChallenge", e);
+ e.printStackTrace();
+ }
+
+ return result.get();
+ }
+
+
+ /**
+ * Generates a unique random challenge in the TEE. A typical use case is to have it wrapped in a
+ * HardwareAuthenticationToken, minted by Gatekeeper upon PIN/Pattern/Password verification.
+ * The HardwareAuthenticationToken can then be sent to the biometric HAL together with a
+ * request to perform sensitive operation(s) (for example enroll), represented by the challenge.
+ * Doing this ensures that a the sensitive operation cannot be performed unless the user has
+ * entered confirmed PIN/Pattern/Password.
+ *
+ * @see com.android.server.locksettings.LockSettingsService
+ *
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
- public long preEnroll() {
- long result = 0;
+ public void generateChallenge(GenerateChallengeCallback callback) {
if (mService != null) try {
- result = mService.preEnroll(mToken);
+ mGenerateChallengeCallback = callback;
+ mService.generateChallenge(mToken, mServiceReceiver, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- return result;
}
/**
@@ -534,14 +586,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
- public int postEnroll() {
- int result = 0;
+ public void revokeChallenge() {
if (mService != null) try {
- result = mService.postEnroll(mToken);
+ mService.revokeChallenge(mToken, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- return result;
}
/**
@@ -760,6 +810,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
case MSG_REMOVED:
sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
break;
+ case MSG_CHALLENGE_GENERATED:
+ sendChallengeGenerated((long) msg.obj /* challenge */);
+ break;
+ default:
+ Slog.w(TAG, "Unknown message: " + msg.what);
+
}
}
};
@@ -839,6 +895,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
+ private void sendChallengeGenerated(long challenge) {
+ if (mGenerateChallengeCallback == null) {
+ Slog.e(TAG, "sendChallengeGenerated, callback null");
+ return;
+ }
+ mGenerateChallengeCallback.onChallengeGenerated(challenge);
+ }
+
/**
* @hide
*/
@@ -846,7 +910,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mContext = context;
mService = service;
if (mService == null) {
- Slog.v(TAG, "FingerprintManagerService was null");
+ Slog.v(TAG, "FingerprintService was null");
}
mHandler = new MyHandler(context);
}
@@ -992,6 +1056,17 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
public void onRemoved(Fingerprint fp, int remaining) {
mHandler.obtainMessage(MSG_REMOVED, remaining, 0, fp).sendToTarget();
}
+
+ @Override // binder call
+ public void onChallengeGenerated(long challenge) {
+ if (mGenerateChallengeCallback instanceof InternalGenerateChallengeCallback) {
+ // Perform this on system_server thread, since the application's thread is
+ // blocked waiting for the result
+ mGenerateChallengeCallback.onChallengeGenerated(challenge);
+ } else {
+ mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, challenge).sendToTarget();
+ }
+ }
};
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index f0c5781f60cb..b72881ace9df 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -76,10 +76,10 @@ interface IFingerprintService {
boolean isHardwareDetected(String opPackageName);
// Get a pre-enrollment authentication token
- long preEnroll(IBinder token);
+ void generateChallenge(IBinder token, IFingerprintServiceReceiver receiver, String opPackageName);
// Finish an enrollment sequence and invalidate the authentication token
- int postEnroll(IBinder token);
+ void revokeChallenge(IBinder token, String opPackageName);
// Determine if a user has at least one enrolled fingerprint
boolean hasEnrolledFingerprints(int userId, String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index 87748a32b40b..3da07b05efb6 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -28,4 +28,5 @@ oneway interface IFingerprintServiceReceiver {
void onAuthenticationFailed();
void onError(int error, int vendorCode);
void onRemoved(in Fingerprint fp, int remaining);
+ void onChallengeGenerated(long challenge);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
index 301bd522e345..4c24d1a61e45 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
@@ -546,6 +546,18 @@ public abstract class BiometricServiceBase extends SystemService
});
}
+ protected void generateChallengeInternal(GenerateChallengeClient client) {
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
+ protected void revokeChallengeInternal(RevokeChallengeClient client) {
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
protected void authenticateInternal(AuthenticationClient client, String opPackageName) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index 342fc7e54434..f4863f59db4d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -119,12 +119,11 @@ public final class ClientMonitorCallbackConverter {
}
}
- // The following are only used internally within system_server - specifically, within
- // BiometricServiceBase and their <Biometric>Service implementations.
-
- void onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)
- throws RemoteException {
- // Currently unused, BiometricServiceBase#handleEnumerate everything internally without
- // needing to propagate this to any receiver.
+ public void onChallengeGenerated(long challenge) throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ mFaceServiceReceiver.onChallengeGenerated(challenge);
+ } else if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onChallengeGenerated(challenge);
+ }
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
new file mode 100644
index 000000000000..98e83daceb6e
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+public abstract class GenerateChallengeClient extends ClientMonitor {
+
+ private static final String TAG = "GenerateChallengeClient";
+
+ protected long mChallenge;
+
+ public GenerateChallengeClient(FinishCallback finishCallback, Context context, IBinder token,
+ ClientMonitorCallbackConverter listener, String owner, int sensorId) {
+ super(finishCallback, context, token, listener, 0 /* userId */, false /* restricted */,
+ owner, 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ }
+
+ @Override
+ public void start() {
+ startHalOperation();
+ try {
+ getListener().onChallengeGenerated(mChallenge);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ mFinishCallback.onClientFinished(this);
+ }
+
+ @Override
+ protected void stopHalOperation() {
+ // Not supported for GenerateChallenge
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
new file mode 100644
index 000000000000..024ff576d230
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.os.IBinder;
+
+public abstract class RevokeChallengeClient extends ClientMonitor {
+
+ public RevokeChallengeClient(FinishCallback finishCallback, Context context, IBinder token,
+ String owner, int sensorId) {
+ super(finishCallback, context, token, null /* listener */, 0 /* userId */,
+ false /* restricted */, owner, 0 /* cookie */, sensorId,
+ BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
+ BiometricsProtoEnums.CLIENT_UNKNOWN);
+ }
+
+ @Override
+ public void start() {
+ startHalOperation();
+ mFinishCallback.onClientFinished(this);
+ }
+
+ @Override
+ protected void stopHalOperation() {
+ // Not supported for RevokeChallenge
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
new file mode 100644
index 000000000000..7d10c59bf828
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.face;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.GenerateChallengeClient;
+
+/**
+ * Face-specific generateChallenge client supporting the
+ * {@link android.hardware.biometrics.face.V1_0} and {@link android.hardware.biometrics.face.V1_1}
+ * HIDL interfaces.
+ */
+public class FaceGenerateChallengeClient extends GenerateChallengeClient {
+
+ private static final String TAG = "FaceGenerateChallengeClient";
+ private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
+
+ private final IBiometricsFace mDaemon;
+
+ FaceGenerateChallengeClient(@NonNull FinishCallback finishCallback,
+ @NonNull Context context, @NonNull IBiometricsFace daemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) {
+ super(finishCallback, context, token, listener, owner, sensorId);
+ mDaemon = daemon;
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ mChallenge = mDaemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "generateChallenge failed", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java
new file mode 100644
index 000000000000..102efda8a45d
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.face;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.RevokeChallengeClient;
+
+/**
+ * Face-specific revokeChallenge client supporting the {@link android.hardware.biometrics.face.V1_0}
+ * and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
+ */
+public class FaceRevokeChallengeClient extends RevokeChallengeClient {
+
+ private static final String TAG = "FaceRevokeChallengeClient";
+
+ private final IBiometricsFace mDaemon;
+
+ FaceRevokeChallengeClient(@NonNull FinishCallback finishCallback, @NonNull Context context,
+ @NonNull IBiometricsFace daemon, @NonNull IBinder token, @NonNull String owner,
+ int sensorId) {
+ super(finishCallback, context, token, owner, sensorId);
+ mDaemon = daemon;
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ mDaemon.revokeChallenge();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "revokeChallenge failed", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 360acd1bf6e4..088762c1f39d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -61,9 +61,11 @@ import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
+import com.android.server.biometrics.sensors.GenerateChallengeClient;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalClient;
+import com.android.server.biometrics.sensors.RevokeChallengeClient;
import org.json.JSONArray;
import org.json.JSONException;
@@ -92,7 +94,7 @@ public class FaceService extends BiometricServiceBase {
private static final String FACE_DATA_DIR = "facedata";
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.biometrics.face.ACTION_LOCKOUT_RESET";
- private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
+
static final String NOTIFICATION_TAG = "FaceService";
static final int NOTIFICATION_ID = 1;
@@ -108,27 +110,46 @@ public class FaceService extends BiometricServiceBase {
*/
@Override // Binder call
- public long generateChallenge(IBinder token) {
+ public void generateChallenge(IBinder token, IFaceServiceReceiver receiver,
+ String opPackageName) throws RemoteException {
checkPermission(MANAGE_BIOMETRIC);
- return startGenerateChallenge(token);
+
+ final IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.e(TAG, "Unable to generateChallenge, daemon null");
+ receiver.onChallengeGenerated(0L);
+ return;
+ }
+
+ final GenerateChallengeClient client = new FaceGenerateChallengeClient(
+ mClientFinishCallback, getContext(), daemon, token,
+ new ClientMonitorCallbackConverter(receiver), opPackageName, getSensorId());
+ generateChallengeInternal(client);
}
@Override // Binder call
- public int revokeChallenge(IBinder token) {
+ public void revokeChallenge(IBinder token, String owner) {
checkPermission(MANAGE_BIOMETRIC);
- mHandler.post(() -> {
- // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
- if (getCurrentClient() == null) {
- // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke
- // the challenge right away.
- startRevokeChallenge(token);
- } else {
- // postpone revoking the challenge until we finish processing the current HIDL
- // call.
- mRevokeChallengePending = true;
- }
- });
- return Status.OK;
+
+ final IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.e(TAG, "Unable to revokeChallenge, daemon null");
+ return;
+ }
+
+ final RevokeChallengeClient client = new FaceRevokeChallengeClient(
+ mClientFinishCallback, getContext(), daemon, token, owner, getSensorId());
+
+ // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
+ if (getCurrentClient() == null) {
+ // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke
+ // the challenge right away.
+ revokeChallengeInternal(client);
+ } else {
+ // postpone revoking the challenge until we finish processing the current HIDL
+ // call.
+ mPendingRevokeChallenge = client;
+ }
}
@Override // Binder call
@@ -480,7 +501,7 @@ public class FaceService extends BiometricServiceBase {
@GuardedBy("this")
private IBiometricsFace mDaemon;
private UsageStats mUsageStats;
- private boolean mRevokeChallengePending = false;
+ private RevokeChallengeClient mPendingRevokeChallenge;
private NotificationManager mNotificationManager;
@@ -615,9 +636,9 @@ public class FaceService extends BiometricServiceBase {
@Override
protected void removeClient(ClientMonitor client) {
super.removeClient(client);
- if (mRevokeChallengePending) {
- startRevokeChallenge(null);
- mRevokeChallengePending = false;
+ if (mPendingRevokeChallenge != null) {
+ revokeChallengeInternal(mPendingRevokeChallenge);
+ mPendingRevokeChallenge = null;
}
}
@@ -806,38 +827,6 @@ public class FaceService extends BiometricServiceBase {
return mDaemon;
}
- private long startGenerateChallenge(IBinder token) {
- IBiometricsFace daemon = getFaceDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startGenerateChallenge: no face HAL!");
- return 0;
- }
- try {
- return daemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
- } catch (RemoteException e) {
- Slog.e(TAG, "startGenerateChallenge failed", e);
- }
- return 0;
- }
-
- private int startRevokeChallenge(IBinder token) {
- IBiometricsFace daemon = getFaceDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startRevokeChallenge: no face HAL!");
- return 0;
- }
- try {
- final int res = daemon.revokeChallenge();
- if (res != Status.OK) {
- Slog.e(TAG, "revokeChallenge returned " + res);
- }
- return res;
- } catch (RemoteException e) {
- Slog.e(TAG, "startRevokeChallenge failed", e);
- }
- return 0;
- }
-
private native NativeHandle convertSurfaceToNativeHandle(Surface surface);
private void dumpInternal(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java
new file mode 100644
index 000000000000..5ff49f377f0a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.fingerprint;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.GenerateChallengeClient;
+
+/**
+ * Fingerprint-specific generateChallenge/preEnroll client supporting the
+ * {@link android.hardware.biometrics.fingerprint.V2_1} and
+ * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces.
+ */
+public class FingerprintGenerateChallengeClient extends GenerateChallengeClient {
+
+ private static final String TAG = "FingerprintGenerateChallengeClient";
+
+ private final IBiometricsFingerprint mDaemon;
+
+ FingerprintGenerateChallengeClient(@NonNull FinishCallback finishCallback,
+ @NonNull Context context, @NonNull IBiometricsFingerprint daemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
+ @NonNull String owner, int sensorId) {
+ super(finishCallback, context, token, listener, owner, sensorId);
+ mDaemon = daemon;
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ mChallenge = mDaemon.preEnroll();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "preEnroll failed", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java
new file mode 100644
index 000000000000..99e9d54b6a5e
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.fingerprint;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.RevokeChallengeClient;
+
+/**
+ * Fingerprint-specific revokeChallenge client supporting the
+ * {@link android.hardware.biometrics.fingerprint.V2_1} and
+ * {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces.
+ */
+public class FingerprintRevokeChallengeClient extends RevokeChallengeClient {
+
+ private static final String TAG = "FingerprintRevokeChallengeClient";
+
+ private final IBiometricsFingerprint mDaemon;
+
+ FingerprintRevokeChallengeClient(@NonNull FinishCallback finishCallback,
+ @NonNull Context context, @NonNull IBiometricsFingerprint daemon,
+ @NonNull IBinder token, @NonNull String owner, int sensorId) {
+ super(finishCallback, context, token, owner, sensorId);
+ mDaemon = daemon;
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ mDaemon.postEnroll();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "revokeChallenge/postEnroll failed", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 893ec6c73674..a4bf22566e98 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -65,9 +65,11 @@ import com.android.server.biometrics.sensors.BiometricServiceBase;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
+import com.android.server.biometrics.sensors.GenerateChallengeClient;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalClient;
+import com.android.server.biometrics.sensors.RevokeChallengeClient;
import org.json.JSONArray;
import org.json.JSONException;
@@ -105,15 +107,36 @@ public class FingerprintService extends BiometricServiceBase {
*/
@Override // Binder call
- public long preEnroll(IBinder token) {
+ public void generateChallenge(IBinder token, IFingerprintServiceReceiver receiver,
+ String opPackageName) throws RemoteException {
checkPermission(MANAGE_FINGERPRINT);
- return startPreEnroll(token);
+
+ final IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.e(TAG, "Unable to generateChallenge, daemon null");
+ receiver.onChallengeGenerated(0L);
+ return;
+ }
+
+ final GenerateChallengeClient client = new FingerprintGenerateChallengeClient(
+ mClientFinishCallback, getContext(), daemon, token,
+ new ClientMonitorCallbackConverter(receiver), opPackageName, getSensorId());
+ generateChallengeInternal(client);
}
@Override // Binder call
- public int postEnroll(IBinder token) {
+ public void revokeChallenge(IBinder token, String owner) {
checkPermission(MANAGE_FINGERPRINT);
- return startPostEnroll(token);
+
+ final IBiometricsFingerprint daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.e(TAG, "startPostEnroll: no fingerprint HAL!");
+ return;
+ }
+
+ final RevokeChallengeClient client = new FingerprintRevokeChallengeClient(
+ mClientFinishCallback, getContext(), daemon, token, owner, getSensorId());
+ revokeChallengeInternal(client);
}
@Override // Binder call
@@ -674,34 +697,6 @@ public class FingerprintService extends BiometricServiceBase {
return mDaemon;
}
- private long startPreEnroll(IBinder token) {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startPreEnroll: no fingerprint HAL!");
- return 0;
- }
- try {
- return daemon.preEnroll();
- } catch (RemoteException e) {
- Slog.e(TAG, "startPreEnroll failed", e);
- }
- return 0;
- }
-
- private int startPostEnroll(IBinder token) {
- IBiometricsFingerprint daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startPostEnroll: no fingerprint HAL!");
- return 0;
- }
- try {
- return daemon.postEnroll();
- } catch (RemoteException e) {
- Slog.e(TAG, "startPostEnroll failed", e);
- }
- return 0;
- }
-
private native NativeHandle convertSurfaceToNativeHandle(Surface surface);
private void dumpInternal(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index bacc43bfd502..66c9c917c567 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2687,7 +2687,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// If there are multiple profiles in the same account, ensure we only generate the
// challenge once.
challengeType = CHALLENGE_INTERNAL;
- challenge = mContext.getSystemService(FaceManager.class).generateChallenge();
+ challenge = mContext.getSystemService(FaceManager.class).generateChallengeBlocking();
}
final AuthenticationResult authResult;