Merge changes I708312ca,Ie51b4e36

* changes:
  2/n: Keep track of IBiometricsFace@1.0 challenge interruptions
  1/n: Slight changes to ClientMonitor's Callback
This commit is contained in:
Kevin Chyn
2020-08-14 00:55:03 +00:00
committed by Android (Google) Code Review
32 changed files with 307 additions and 144 deletions

View File

@@ -72,6 +72,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
private static final int MSG_SET_FEATURE_COMPLETED = 107;
private static final int MSG_CHALLENGE_GENERATED = 108;
private static final int MSG_FACE_DETECTED = 109;
private static final int MSG_CHALLENGE_INTERRUPTED = 110;
private static final int MSG_CHALLENGE_INTERRUPT_FINISHED = 111;
private final IFaceService mService;
private final Context mContext;
@@ -150,6 +152,16 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, challenge).sendToTarget();
}
}
@Override
public void onChallengeInterrupted(int sensorId) {
mHandler.obtainMessage(MSG_CHALLENGE_INTERRUPTED, sensorId).sendToTarget();
}
@Override
public void onChallengeInterruptFinished(int sensorId) {
mHandler.obtainMessage(MSG_CHALLENGE_INTERRUPT_FINISHED, sensorId).sendToTarget();
}
};
/**
@@ -1071,10 +1083,25 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
* Callback structure provided to {@link #generateChallenge(GenerateChallengeCallback)}.
* @hide
*/
public interface GenerateChallengeCallback {
/**
* Invoked when a challenge has been generated.
*/
void onGenerateChallengeResult(long challenge);
/**
* Invoked if the challenge has not been revoked and a subsequent caller/owner invokes
* {@link #generateChallenge(GenerateChallengeCallback)}, but
*/
default void onChallengeInterrupted(int sensorId) {}
/**
* Invoked when the interrupting client has finished (e.g. revoked its challenge).
*/
default void onChallengeInterruptFinished(int sensorId) {}
}
private abstract static class InternalGenerateChallengeCallback
@@ -1157,6 +1184,12 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
sendFaceDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
(boolean) msg.obj /* isStrongBiometric */);
break;
case MSG_CHALLENGE_INTERRUPTED:
sendChallengeInterrupted((int) msg.obj /* sensorId */);
break;
case MSG_CHALLENGE_INTERRUPT_FINISHED:
sendChallengeInterruptFinished((int) msg.obj /* sensorId */);
break;
default:
Slog.w(TAG, "Unknown message: " + msg.what);
}
@@ -1193,6 +1226,22 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mFaceDetectionCallback.onFaceDetected(sensorId, userId, isStrongBiometric);
}
private void sendChallengeInterrupted(int sensorId) {
if (mGenerateChallengeCallback == null) {
Slog.e(TAG, "sendChallengeInterrupted, callback null");
return;
}
mGenerateChallengeCallback.onChallengeInterrupted(sensorId);
}
private void sendChallengeInterruptFinished(int sensorId) {
if (mGenerateChallengeCallback == null) {
Slog.e(TAG, "sendChallengeInterruptFinished, callback null");
return;
}
mGenerateChallengeCallback.onChallengeInterruptFinished(sensorId);
}
private void sendRemovedResult(Face face, int remaining) {
if (mRemovalCallback == null) {
return;

View File

@@ -32,4 +32,6 @@ oneway interface IFaceServiceReceiver {
void onFeatureSet(boolean success, int feature);
void onFeatureGet(boolean success, int feature, boolean value);
void onChallengeGenerated(long challenge);
void onChallengeInterrupted(int sensorId);
void onChallengeInterruptFinished(int sensorId);
}

View File

@@ -98,7 +98,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
}
if (finish) {
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -114,7 +114,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
}
@Override
public void cancelWithoutStarting(@NonNull FinishCallback finishCallback) {
public void cancelWithoutStarting(@NonNull Callback callback) {
final int errorCode = BiometricConstants.BIOMETRIC_ERROR_CANCELED;
try {
if (getListener() != null) {
@@ -123,7 +123,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke sendError", e);
}
finishCallback.onClientFinished(this, true /* success */);
callback.onClientFinished(this, true /* success */);
}
/**
@@ -155,7 +155,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke sendAcquired", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}

View File

@@ -191,7 +191,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
}
} catch (RemoteException e) {
Slog.e(TAG, "Unable to notify listener, finishing", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -211,8 +211,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
* Start authentication
*/
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutTracker.getLockoutModeForUser(getTargetUserId());

View File

@@ -85,7 +85,7 @@ public class BiometricScheduler {
static final int STATE_WAITING_FOR_COOKIE = 4;
/**
* The {@link ClientMonitor.FinishCallback} has been invoked and the client is finished.
* The {@link ClientMonitor.Callback} has been invoked and the client is finished.
*/
static final int STATE_FINISHED = 5;
@@ -99,13 +99,13 @@ public class BiometricScheduler {
@interface OperationState {}
@NonNull final ClientMonitor<?> clientMonitor;
@Nullable final ClientMonitor.FinishCallback clientFinishCallback;
@Nullable final ClientMonitor.Callback mClientCallback;
@OperationState int state;
Operation(@NonNull ClientMonitor<?> clientMonitor,
@Nullable ClientMonitor.FinishCallback finishCallback) {
@Nullable ClientMonitor.Callback callback) {
this.clientMonitor = clientMonitor;
this.clientFinishCallback = finishCallback;
this.mClientCallback = callback;
state = STATE_WAITING_IN_QUEUE;
}
@@ -133,7 +133,7 @@ public class BiometricScheduler {
public void run() {
if (operation.state != Operation.STATE_FINISHED) {
Slog.e(tag, "[Watchdog Triggered]: " + operation);
operation.clientMonitor.mFinishCallback
operation.clientMonitor.mCallback
.onClientFinished(operation.clientMonitor, false /* success */);
}
}
@@ -175,15 +175,15 @@ public class BiometricScheduler {
@Nullable private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@NonNull private final IBiometricService mBiometricService;
@NonNull private final Handler mHandler = new Handler(Looper.getMainLooper());
@NonNull private final InternalFinishCallback mInternalFinishCallback;
@NonNull protected final InternalCallback mInternalCallback;
@NonNull private final Queue<Operation> mPendingOperations;
@Nullable private Operation mCurrentOperation;
@NonNull private final ArrayDeque<CrashState> mCrashStates;
// Internal finish callback, notified when an operation is complete. Notifies the requester
// Internal callback, notified when an operation is complete. Notifies the requester
// that the operation is complete, before performing internal scheduler work (such as
// starting the next client).
private class InternalFinishCallback implements ClientMonitor.FinishCallback {
public class InternalCallback implements ClientMonitor.Callback {
@Override
public void onClientFinished(ClientMonitor<?> clientMonitor, boolean success) {
mHandler.post(() -> {
@@ -203,8 +203,8 @@ public class BiometricScheduler {
Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success);
mCurrentOperation.state = Operation.STATE_FINISHED;
if (mCurrentOperation.clientFinishCallback != null) {
mCurrentOperation.clientFinishCallback.onClientFinished(clientMonitor, success);
if (mCurrentOperation.mClientCallback != null) {
mCurrentOperation.mClientCallback.onClientFinished(clientMonitor, success);
}
if (mGestureAvailabilityDispatcher != null) {
@@ -227,7 +227,7 @@ public class BiometricScheduler {
public BiometricScheduler(@NonNull String tag,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
mBiometricTag = tag;
mInternalFinishCallback = new InternalFinishCallback();
mInternalCallback = new InternalCallback();
mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
mPendingOperations = new ArrayDeque<>();
mBiometricService = IBiometricService.Stub.asInterface(
@@ -262,7 +262,7 @@ public class BiometricScheduler {
}
final Interruptable interruptable = (Interruptable) currentClient;
interruptable.cancelWithoutStarting(mInternalFinishCallback);
interruptable.cancelWithoutStarting(mInternalCallback);
// Now we wait for the client to send its FinishCallback, which kicks off the next
// operation.
return;
@@ -280,7 +280,10 @@ public class BiometricScheduler {
final boolean shouldStartNow = currentClient.getCookie() == 0;
if (shouldStartNow) {
Slog.d(getTag(), "[Starting] " + mCurrentOperation);
currentClient.start(mInternalFinishCallback);
if (mCurrentOperation.mClientCallback != null) {
mCurrentOperation.mClientCallback.onClientStarted(currentClient);
}
currentClient.start(mInternalCallback);
mCurrentOperation.state = Operation.STATE_STARTED;
} else {
try {
@@ -323,8 +326,11 @@ public class BiometricScheduler {
}
Slog.d(getTag(), "[Starting] Prepared client: " + mCurrentOperation);
if (mCurrentOperation.mClientCallback != null) {
mCurrentOperation.mClientCallback.onClientStarted(mCurrentOperation.clientMonitor);
}
mCurrentOperation.state = Operation.STATE_STARTED;
mCurrentOperation.clientMonitor.start(mInternalFinishCallback);
mCurrentOperation.clientMonitor.start(mInternalCallback);
}
/**
@@ -340,11 +346,11 @@ public class BiometricScheduler {
* Adds a {@link ClientMonitor} to the pending queue
*
* @param clientMonitor operation to be scheduled
* @param clientFinishCallback optional callback, invoked when the client is finished, but
* @param clientCallback optional callback, invoked when the client is finished, but
* before it has been removed from the queue.
*/
public void scheduleClientMonitor(@NonNull ClientMonitor<?> clientMonitor,
@Nullable ClientMonitor.FinishCallback clientFinishCallback) {
@Nullable ClientMonitor.Callback clientCallback) {
// Mark any interruptable pending clients as canceling. Once they reach the head of the
// queue, the scheduler will send ERROR_CANCELED and skip the operation.
for (Operation operation : mPendingOperations) {
@@ -356,7 +362,7 @@ public class BiometricScheduler {
}
}
mPendingOperations.add(new Operation(clientMonitor, clientFinishCallback));
mPendingOperations.add(new Operation(clientMonitor, clientCallback));
Slog.d(getTag(), "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());

View File

@@ -42,7 +42,15 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
/**
* Interface that ClientMonitor holders should use to receive callbacks.
*/
public interface FinishCallback {
public interface Callback {
/**
* Invoked when the ClientMonitor operation has been started (e.g. reached the head of
* the queue and becomes the current operation).
*
* @param clientMonitor Reference of the ClientMonitor that is starting.
*/
default void onClientStarted(@NonNull ClientMonitor<?> clientMonitor) {}
/**
* Invoked when the ClientMonitor operation is complete. This abstracts away asynchronous
* (i.e. Authenticate, Enroll, Enumerate, Remove) and synchronous (i.e. generateChallenge,
@@ -52,7 +60,7 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
* @param clientMonitor Reference of the ClientMonitor that finished.
* @param success True if the operation completed successfully.
*/
void onClientFinished(ClientMonitor<?> clientMonitor, boolean success);
default void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) {}
}
/**
@@ -79,7 +87,7 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
private final int mCookie;
boolean mAlreadyDone;
@NonNull protected FinishCallback mFinishCallback;
@NonNull protected Callback mCallback;
/**
* @param context system_server context
@@ -125,17 +133,17 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
/**
* Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null).
* If such a problem is detected, the scheduler will not invoke
* {@link #start(FinishCallback)}.
* {@link #start(Callback)}.
*/
public abstract void unableToStart();
/**
* Starts the ClientMonitor's lifecycle. Invokes {@link #startHalOperation()} when internal book
* keeping is complete.
* @param finishCallback invoked when the operation is complete (succeeds, fails, etc)
* @param callback invoked when the operation is complete (succeeds, fails, etc)
*/
public void start(@NonNull FinishCallback finishCallback) {
mFinishCallback = finishCallback;
public void start(@NonNull Callback callback) {
mCallback = callback;
}
/**

View File

@@ -142,10 +142,21 @@ public final class ClientMonitorCallbackConverter {
}
}
public void onFeatureGet(boolean success, int feature, boolean value)
throws RemoteException {
public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException {
if (mFaceServiceReceiver != null) {
mFaceServiceReceiver.onFeatureGet(success, feature, value);
}
}
public void onChallengeInterrupted(int sensorId) throws RemoteException {
if (mFaceServiceReceiver != null) {
mFaceServiceReceiver.onChallengeInterrupted(sensorId);
}
}
public void onChallengeInterruptFinished(int sensorId) throws RemoteException {
if (mFaceServiceReceiver != null) {
mFaceServiceReceiver.onChallengeInterruptFinished(sensorId);
}
}
}

View File

@@ -77,18 +77,18 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(), identifier);
logOnEnrolled(getTargetUserId(), System.currentTimeMillis() - mEnrollmentStartTimeMs,
true /* enrollSuccessful */);
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
}
notifyUserActivity();
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
if (hasReachedEnrollmentLimit()) {
Slog.e(TAG, "Reached enrollment limit");
finishCallback.onClientFinished(this, false /* success */);
callback.onClientFinished(this, false /* success */);
return;
}

View File

@@ -47,16 +47,16 @@ public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> {
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
startHalOperation();
try {
getListener().onChallengeGenerated(mChallenge);
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -62,29 +62,35 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
private final List<S> mEnrolledList;
private ClientMonitor<T> mCurrentTask;
private final FinishCallback mEnumerateFinishCallback = (clientMonitor, success) -> {
final List<BiometricAuthenticator.Identifier> unknownHALTemplates =
((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates();
private final Callback mEnumerateCallback = new Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) {
final List<BiometricAuthenticator.Identifier> unknownHALTemplates =
((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates();
if (!unknownHALTemplates.isEmpty()) {
Slog.w(TAG, "Adding " + unknownHALTemplates.size() + " templates for deletion");
}
for (BiometricAuthenticator.Identifier unknownHALTemplate : unknownHALTemplates) {
mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplate,
mCurrentTask.getTargetUserId()));
}
if (!unknownHALTemplates.isEmpty()) {
Slog.w(TAG, "Adding " + unknownHALTemplates.size() + " templates for deletion");
}
for (BiometricAuthenticator.Identifier unknownHALTemplate : unknownHALTemplates) {
mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplate,
mCurrentTask.getTargetUserId()));
}
if (mUnknownHALTemplates.isEmpty()) {
// No unknown HAL templates. Unknown framework templates are already cleaned up in
// InternalEnumerateClient. Finish this client.
mFinishCallback.onClientFinished(this, success);
} else {
startCleanupUnknownHalTemplates();
if (mUnknownHALTemplates.isEmpty()) {
// No unknown HAL templates. Unknown framework templates are already cleaned up in
// InternalEnumerateClient. Finish this client.
mCallback.onClientFinished(InternalCleanupClient.this, success);
} else {
startCleanupUnknownHalTemplates();
}
}
};
private final FinishCallback mRemoveFinishCallback = (clientMonitor, success) -> {
mFinishCallback.onClientFinished(this, success);
private final Callback mRemoveCallback = new Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) {
mCallback.onClientFinished(InternalCleanupClient.this, success);
}
};
protected abstract InternalEnumerateClient<T> getEnumerateClient(Context context,
@@ -116,7 +122,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
mStatsModality,
BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
mCurrentTask.start(mRemoveFinishCallback);
mCurrentTask.start(mRemoveCallback);
}
@Override
@@ -125,13 +131,13 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
// Start enumeration. Removal will start if necessary, when enumeration is completed.
mCurrentTask = getEnumerateClient(getContext(), mLazyDaemon, getToken(), getTargetUserId(),
getOwnerString(), mEnrolledList, mBiometricUtils, getSensorId());
mCurrentTask.start(mEnumerateFinishCallback);
mCurrentTask.start(mEnumerateCallback);
}
@Override
@@ -147,7 +153,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
+ mCurrentTask.getClass().getSimpleName());
return;
}
((RemovalClient) mCurrentTask).onRemoved(identifier, remaining);
((RemovalClient<T>) mCurrentTask).onRemoved(identifier, remaining);
}
@Override

View File

@@ -62,7 +62,7 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
handleEnumeratedTemplate(identifier);
if (remaining == 0) {
doTemplateCleanup();
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
}
}
@@ -72,8 +72,8 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
// The biometric template ids will be removed when we get confirmation from the HAL
startHalOperation();

View File

@@ -37,10 +37,10 @@ public interface Interruptable {
/**
* Notifies the client that it needs to finish before
* {@link ClientMonitor#start(ClientMonitor.FinishCallback)} was invoked. This usually happens
* {@link ClientMonitor#start(ClientMonitor.Callback)} was invoked. This usually happens
* if the client is still waiting in the pending queue and got notified that a subsequent
* operation is preempting it.
* @param finishCallback invoked when the operation is completed.
* @param callback invoked when the operation is completed.
*/
void cancelWithoutStarting(@NonNull ClientMonitor.FinishCallback finishCallback);
void cancelWithoutStarting(@NonNull ClientMonitor.Callback callback);
}

View File

@@ -55,8 +55,8 @@ public abstract class RemovalClient<T> extends ClientMonitor<T> implements Remov
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
// The biometric template ids will be removed when we get confirmation from the HAL
startHalOperation();
@@ -85,7 +85,7 @@ public abstract class RemovalClient<T> extends ClientMonitor<T> implements Remov
// cleanup).
mAuthenticatorIds.put(getTargetUserId(), 0L);
}
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
}
}
}

View File

@@ -36,10 +36,10 @@ public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> {
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
startHalOperation();
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
}
}

View File

@@ -98,6 +98,11 @@ class Face10 implements IHwBinder.DeathRecipient {
@Nullable private IBiometricsFace mDaemon;
private int mCurrentUserId = UserHandle.USER_NULL;
// If a challenge is generated, keep track of its owner. Since IBiometricsFace@1.0 only
// supports a single in-flight challenge, we must notify the interrupted owner that its
// challenge is no longer valid. The interrupted owner will be notified when the interrupter
// has finished.
@Nullable private FaceGenerateChallengeClient mCurrentChallengeOwner;
private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() {
@Override
@@ -394,9 +399,12 @@ class Face10 implements IHwBinder.DeathRecipient {
final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext,
mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, mCurrentUserId,
hasEnrolled, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client, (clientMonitor, success) -> {
if (success) {
mCurrentUserId = targetUserId;
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) {
if (success) {
mCurrentUserId = targetUserId;
}
}
});
}
@@ -459,18 +467,68 @@ class Face10 implements IHwBinder.DeathRecipient {
void scheduleGenerateChallenge(@NonNull IBinder token, @NonNull IFaceServiceReceiver receiver,
@NonNull String opPackageName) {
mHandler.post(() -> {
if (mCurrentChallengeOwner != null) {
Slog.w(TAG, "Current challenge owner: " + mCurrentChallengeOwner
+ ", interrupted by: " + opPackageName);
try {
mCurrentChallengeOwner.getListener().onChallengeInterrupted(mSensorId);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to notify challenge interrupted", e);
}
}
final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), opPackageName,
mSensorId);
mScheduler.scheduleClientMonitor(client);
mSensorId, mCurrentChallengeOwner);
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
public void onClientStarted(@NonNull ClientMonitor<?> clientMonitor) {
if (client != clientMonitor) {
Slog.e(TAG, "scheduleGenerateChallenge, mismatched client."
+ " Expecting: " + client + ", received: " + clientMonitor);
return;
}
Slog.d(TAG, "Current challenge owner: " + client);
mCurrentChallengeOwner = client;
}
});
});
}
void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String owner) {
mHandler.post(() -> {
if (!mCurrentChallengeOwner.getOwnerString().contentEquals(owner)) {
Slog.e(TAG, "Package: " + owner + " attempting to revoke challenge owned by: "
+ mCurrentChallengeOwner.getOwnerString());
return;
}
final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
mLazyDaemon, token, owner, mSensorId);
mScheduler.scheduleClientMonitor(client);
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor,
boolean success) {
if (client != clientMonitor) {
Slog.e(TAG, "scheduleRevokeChallenge, mismatched client."
+ "Expecting: " + client + ", received: " + clientMonitor);
return;
}
final FaceGenerateChallengeClient previousChallengeOwner =
mCurrentChallengeOwner.getInterruptedClient();
mCurrentChallengeOwner = null;
Slog.d(TAG, "Previous challenge owner: " + previousChallengeOwner);
if (previousChallengeOwner != null) {
try {
previousChallengeOwner.getListener()
.onChallengeInterruptFinished(mSensorId);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to notify interrupt finished", e);
}
}
}
});
});
}
@@ -488,12 +546,16 @@ class Face10 implements IHwBinder.DeathRecipient {
opPackageName, FaceUtils.getInstance(), disabledFeatures, ENROLL_TIMEOUT_SEC,
surfaceHandle, mSensorId);
mScheduler.scheduleClientMonitor(client, ((clientMonitor, success) -> {
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(client.getTargetUserId());
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor,
boolean success) {
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(client.getTargetUserId());
}
}
}));
});
});
}

View File

@@ -92,7 +92,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -103,7 +103,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -131,7 +131,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
// 1) Authenticated == true
// 2) Error occurred
// 3) Authenticated == false
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
}
@Override

View File

@@ -116,12 +116,12 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
}
if (status != Status.OK) {
onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -132,7 +132,7 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -17,12 +17,14 @@
package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.annotation.Nullable;
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.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.GenerateChallengeClient;
@@ -36,10 +38,22 @@ public class FaceGenerateChallengeClient extends GenerateChallengeClient<IBiomet
private static final String TAG = "FaceGenerateChallengeClient";
private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
// If `this` FaceGenerateChallengeClient was invoked while an existing in-flight challenge
// was not revoked yet, store a reference to the interrupted client here. Notify the interrupted
// client when `this` challenge is revoked.
@Nullable private final FaceGenerateChallengeClient mInterruptedClient;
FaceGenerateChallengeClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) {
@NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId,
@Nullable FaceGenerateChallengeClient interruptedClient) {
super(context, lazyDaemon, token, listener, owner, sensorId);
mInterruptedClient = interruptedClient;
}
@Nullable
public FaceGenerateChallengeClient getInterruptedClient() {
return mInterruptedClient;
}
@Override

View File

@@ -61,8 +61,8 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
startHalOperation();
}
@@ -71,10 +71,10 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
try {
final OptionalBool result = getFreshDaemon().getFeature(mFeature, mFaceId);
getListener().onFeatureGet(result.status == Status.OK, mFeature, result.value);
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to getFeature", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -52,7 +52,7 @@ class FaceInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFac
getFreshDaemon().enumerate();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enumerate", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -51,7 +51,7 @@ class FaceRemovalClient extends RemovalClient<IBiometricsFace> {
getFreshDaemon().remove(mBiometricId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting remove", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -56,8 +56,8 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> {
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
startHalOperation();
}
@@ -65,10 +65,10 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> {
protected void startHalOperation() {
try {
getFreshDaemon().resetLockout(mHardwareAuthToken);
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to reset lockout", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -70,8 +70,8 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> {
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
startHalOperation();
}
@@ -82,10 +82,10 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> {
final int result = getFreshDaemon()
.setFeature(mFeature, mEnabled, mHardwareAuthToken, mFaceId);
getListener().onFeatureSet(result == Status.OK, mFeature);
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -50,8 +50,8 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> {
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
if (mCurrentUserId == getTargetUserId()) {
Slog.d(TAG, "Already user: " + mCurrentUserId + ", refreshing authenticatorId");
@@ -61,7 +61,7 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> {
} catch (RemoteException e) {
Slog.e(TAG, "Unable to refresh authenticatorId", e);
}
finishCallback.onClientFinished(this, true /* success */);
callback.onClientFinished(this, true /* success */);
return;
}
@@ -79,16 +79,16 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> {
FACE_DATA_DIR);
if (!storePath.exists()) {
Slog.e(TAG, "vold has not created the directory?");
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
return;
}
try {
getFreshDaemon().setActiveUser(getTargetUserId(), storePath.getAbsolutePath());
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveUser: " + e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -409,9 +409,12 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId,
mContext.getOpPackageName(), mSensorProperties.sensorId, mCurrentUserId,
hasEnrolled, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client, (clientMonitor, success) -> {
if (success) {
mCurrentUserId = targetUserId;
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) {
if (success) {
mCurrentUserId = targetUserId;
}
}
});
}
@@ -453,12 +456,16 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
hardwareAuthToken, opPackageName, FingerprintUtils.getInstance(),
ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController);
mScheduler.scheduleClientMonitor(client, ((clientMonitor, success) -> {
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId());
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor,
boolean success) {
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId());
}
}
}));
});
});
}

View File

@@ -79,7 +79,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
if (authenticated) {
resetFailedAttempts(getTargetUserId());
UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
} else {
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
@@ -119,7 +119,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -132,7 +132,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}

View File

@@ -68,13 +68,13 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
startHalOperation();
}
@@ -88,7 +88,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}

View File

@@ -79,7 +79,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -92,7 +92,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}

View File

@@ -52,7 +52,7 @@ class FingerprintInternalEnumerateClient extends InternalEnumerateClient<IBiomet
getFreshDaemon().enumerate();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enumerate", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -54,7 +54,7 @@ class FingerprintRemovalClient extends RemovalClient<IBiometricsFingerprint> {
getFreshDaemon().remove(getTargetUserId(), mBiometricId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting remove", e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -22,7 +22,6 @@ import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SELinux;
import android.util.Slog;
@@ -58,8 +57,8 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics
}
@Override
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
public void start(@NonNull Callback callback) {
super.start(callback);
if (mCurrentUserId == getTargetUserId()) {
Slog.d(TAG, "Already user: " + mCurrentUserId + ", refreshing authenticatorId");
@@ -69,7 +68,7 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics
} catch (RemoteException e) {
Slog.e(TAG, "Unable to refresh authenticatorId", e);
}
finishCallback.onClientFinished(this, true /* success */);
callback.onClientFinished(this, true /* success */);
return;
}
@@ -89,7 +88,7 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics
if (!mDirectory.exists()) {
if (!mDirectory.mkdir()) {
Slog.e(TAG, "Cannot make directory: " + mDirectory.getAbsolutePath());
finishCallback.onClientFinished(this, false /* success */);
callback.onClientFinished(this, false /* success */);
return;
}
// Calling mkdir() from this process will create a directory with our
@@ -97,7 +96,7 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics
// the label.
if (!SELinux.restorecon(mDirectory)) {
Slog.e(TAG, "Restorecons failed. Directory will have wrong label.");
finishCallback.onClientFinished(this, false /* success */);
callback.onClientFinished(this, false /* success */);
return;
}
}
@@ -116,10 +115,10 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics
getFreshDaemon().setActiveGroup(getTargetUserId(), mDirectory.getAbsolutePath());
mAuthenticatorIds.put(getTargetUserId(), mHasEnrolledBiometrics
? getFreshDaemon().getAuthenticatorId() : 0L);
mFinishCallback.onClientFinished(this, true /* success */);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveGroup: " + e);
mFinishCallback.onClientFinished(this, false /* success */);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -17,7 +17,6 @@
package com.android.server.biometrics.sensors;
import android.content.Context;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import androidx.annotation.NonNull;
@@ -56,8 +55,8 @@ public class BiometricSchedulerTest {
mScheduler.scheduleClientMonitor(client1);
mScheduler.scheduleClientMonitor(client2);
client1.mFinishCallback.onClientFinished(client1, true /* success */);
client1.mFinishCallback.onClientFinished(client1, true /* success */);
client1.mCallback.onClientFinished(client1, true /* success */);
client1.mCallback.onClientFinished(client1, true /* success */);
}
private static class TestClientMonitor extends ClientMonitor<Object> {