From f54020f2b1012f7cb3d7b6251fbd36bd4b95a8ec Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Fri, 6 Nov 2020 14:26:02 -0800 Subject: [PATCH] Implement client monitors for face AIDL This CL implements all of the monitors except for FaceGetFeatureClient and FaceSetFeatureClient because the get/set feature methods aren't currently supported in the AIDL interface. Bug: 171335732 Test: build Change-Id: Ib6eaff5d7a323b8e9333ca8408ec69f488108a31 --- services/core/Android.bp | 1 + .../face/aidl/FaceAuthenticationClient.java | 221 ++++++++++++++++++ .../sensors/face/aidl/FaceEnrollClient.java | 120 ++++++++++ .../aidl/FaceGenerateChallengeClient.java | 61 +++++ .../aidl/FaceGetAuthenticatorIdClient.java | 63 +++++ .../face/aidl/FaceInternalCleanupClient.java | 67 ++++++ .../aidl/FaceInternalEnumerateClient.java | 57 +++++ .../sensors/face/aidl/FaceRemovalClient.java | 59 +++++ .../face/aidl/FaceResetLockoutClient.java | 79 +++++++ .../face/aidl/FaceRevokeChallengeClient.java | 58 +++++ 10 files changed, 786 insertions(+) create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java diff --git a/services/core/Android.bp b/services/core/Android.bp index ff47a83b01153..fb3c61bc54bce 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -110,6 +110,7 @@ java_library_static { "android.hardware.tv.cec-V1.0-java", "android.hardware.weaver-V1.0-java", "android.hardware.biometrics.face-V1.1-java", + "android.hardware.biometrics.face-java", "android.hardware.biometrics.fingerprint-V2.3-java", "android.hardware.biometrics.fingerprint-java", "android.hardware.oemlock-V1.0-java", diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java new file mode 100644 index 0000000000000..80f337f0f6000 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -0,0 +1,221 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.NotificationManager; +import android.content.Context; +import android.content.res.Resources; +import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricConstants; +import android.hardware.biometrics.BiometricFaceConstants; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.common.ICancellationSignal; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.hardware.face.FaceManager; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.R; +import com.android.server.biometrics.Utils; +import com.android.server.biometrics.sensors.AuthenticationClient; +import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; +import com.android.server.biometrics.sensors.LockoutCache; +import com.android.server.biometrics.sensors.LockoutConsumer; +import com.android.server.biometrics.sensors.LockoutTracker; +import com.android.server.biometrics.sensors.face.UsageStats; + +import java.util.ArrayList; + +/** + * Face-specific authentication client for the {@link IFace} AIDL HAL interface. + */ +class FaceAuthenticationClient extends AuthenticationClient implements LockoutConsumer { + private static final String TAG = "FaceAuthenticationClient"; + + @NonNull private final UsageStats mUsageStats; + @NonNull private final LockoutCache mLockoutCache; + @Nullable private final NotificationManager mNotificationManager; + @Nullable private ICancellationSignal mCancellationSignal; + + private final int[] mBiometricPromptIgnoreList; + private final int[] mBiometricPromptIgnoreListVendor; + private final int[] mKeyguardIgnoreList; + private final int[] mKeyguardIgnoreListVendor; + + private int mLastAcquire; + + FaceAuthenticationClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, + boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId, + boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats, + @NonNull LockoutCache lockoutCache) { + super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, + owner, cookie, requireConfirmation, sensorId, isStrongBiometric, + BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */, + lockoutCache); + mUsageStats = usageStats; + mLockoutCache = lockoutCache; + mNotificationManager = context.getSystemService(NotificationManager.class); + + final Resources resources = getContext().getResources(); + mBiometricPromptIgnoreList = resources.getIntArray( + R.array.config_face_acquire_biometricprompt_ignorelist); + mBiometricPromptIgnoreListVendor = resources.getIntArray( + R.array.config_face_acquire_vendor_biometricprompt_ignorelist); + mKeyguardIgnoreList = resources.getIntArray( + R.array.config_face_acquire_keyguard_ignorelist); + mKeyguardIgnoreListVendor = resources.getIntArray( + R.array.config_face_acquire_vendor_keyguard_ignorelist); + } + + @Override + protected void startHalOperation() { + try { + mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting auth", e); + onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + } + + @Override + protected void stopHalOperation() { + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting cancel", e); + onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + } + } + + private boolean wasUserDetected() { + // Do not provide haptic feedback if the user was not detected, and an error (usually + // ERROR_TIMEOUT) is received. + return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED + && mLastAcquire != FaceManager.FACE_ACQUIRED_SENSOR_DIRTY; + } + + @Override + public void onAuthenticated(BiometricAuthenticator.Identifier identifier, + boolean authenticated, ArrayList token) { + super.onAuthenticated(identifier, authenticated, token); + + mUsageStats.addEvent(new UsageStats.AuthenticationEvent( + getStartTimeMs(), + System.currentTimeMillis() - getStartTimeMs() /* latency */, + authenticated, + 0 /* error */, + 0 /* vendorError */, + getTargetUserId())); + + // For face, the authentication lifecycle ends either when + // 1) Authenticated == true + // 2) Error occurred + // 3) Authenticated == false + mCallback.onClientFinished(this, true /* success */); + } + + @Override + public void onError(int error, int vendorCode) { + mUsageStats.addEvent(new UsageStats.AuthenticationEvent( + getStartTimeMs(), + System.currentTimeMillis() - getStartTimeMs() /* latency */, + false /* authenticated */, + error, + vendorCode, + getTargetUserId())); + + switch (error) { + case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT: + if (!wasUserDetected() && !isBiometricPrompt()) { + // No vibration if user was not detected on keyguard + break; + } + case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT: + case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT: + if (mAuthAttempted) { + // Only vibrate if auth was attempted. If the user was already locked out prior + // to starting authentication, do not vibrate. + vibrateError(); + } + break; + default: + break; + } + + super.onError(error, vendorCode); + } + + private int[] getAcquireIgnorelist() { + return isBiometricPrompt() ? mBiometricPromptIgnoreList : mKeyguardIgnoreList; + } + + private int[] getAcquireVendorIgnorelist() { + return isBiometricPrompt() ? mBiometricPromptIgnoreListVendor : mKeyguardIgnoreListVendor; + } + + private boolean shouldSend(int acquireInfo, int vendorCode) { + if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) { + return !Utils.listContains(getAcquireVendorIgnorelist(), vendorCode); + } else { + return !Utils.listContains(getAcquireIgnorelist(), acquireInfo); + } + } + + @Override + public void onAcquired(int acquireInfo, int vendorCode) { + mLastAcquire = acquireInfo; + + final boolean shouldSend = shouldSend(acquireInfo, vendorCode); + onAcquiredInternal(acquireInfo, vendorCode, shouldSend); + } + + @Override public void onLockoutTimed(long durationMillis) { + mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED); + // Lockout metrics are logged as an error code. + final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT; + logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId()); + + try { + getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + } + + @Override public void onLockoutPermanent() { + mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT); + // Lockout metrics are logged as an error code. + final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; + logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId()); + + try { + getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java new file mode 100644 index 0000000000000..f950862bacd9a --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java @@ -0,0 +1,120 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.hardware.biometrics.BiometricFaceConstants; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.common.ICancellationSignal; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.hardware.face.Face; +import android.hardware.face.FaceManager; +import android.os.IBinder; +import android.os.NativeHandle; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.R; +import com.android.server.biometrics.HardwareAuthTokenUtils; +import com.android.server.biometrics.Utils; +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.face.FaceUtils; + +import java.util.ArrayList; + +/** + * Face-specific enroll client for the {@link IFace} AIDL HAL interface. + */ +public class FaceEnrollClient extends EnrollClient { + + private static final String TAG = "FaceEnrollClient"; + + @NonNull private final int[] mEnrollIgnoreList; + @NonNull private final int[] mEnrollIgnoreListVendor; + @Nullable private ICancellationSignal mCancellationSignal; + private final int mMaxTemplatesPerUser; + + FaceEnrollClient(@NonNull Context context, @NonNull LazyDaemon lazyDaemon, + @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, + @NonNull byte[] hardwareAuthToken, @NonNull String opPackageName, + @NonNull BiometricUtils utils, @NonNull int[] disabledFeatures, int timeoutSec, + @Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser) { + super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils, + timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId, + false /* shouldVibrate */); + mEnrollIgnoreList = getContext().getResources() + .getIntArray(R.array.config_face_acquire_enroll_ignorelist); + mEnrollIgnoreListVendor = getContext().getResources() + .getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist); + mMaxTemplatesPerUser = maxTemplatesPerUser; + } + + @Override + protected boolean hasReachedEnrollmentLimit() { + return FaceUtils.getInstance(getSensorId()).getBiometricsForUser(getContext(), + getTargetUserId()).size() >= mMaxTemplatesPerUser; + } + + @Override + public void onAcquired(int acquireInfo, int vendorCode) { + final boolean shouldSend; + if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) { + shouldSend = !Utils.listContains(mEnrollIgnoreListVendor, vendorCode); + } else { + shouldSend = !Utils.listContains(mEnrollIgnoreList, acquireInfo); + } + onAcquiredInternal(acquireInfo, vendorCode, shouldSend); + } + + @Override + protected void startHalOperation() { + final ArrayList token = new ArrayList<>(); + for (byte b : mHardwareAuthToken) { + token.add(b); + } + + try { + // TODO(b/172593978): Pass features. + // TODO(b/172593521): Pass mPreviewSurface as android.hardware.common.NativeHandle. + mCancellationSignal = getFreshDaemon().enroll(mSequentialId, + HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken), + null /* mPreviewSurface */); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting enroll", e); + onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + } + + @Override + protected void stopHalOperation() { + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting cancel", e); + onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java new file mode 100644 index 0000000000000..d7e08e4627777 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java @@ -0,0 +1,61 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +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 for the {@link IFace} AIDL HAL interface. + */ +public class FaceGenerateChallengeClient extends GenerateChallengeClient { + private static final String TAG = "FaceGenerateChallengeClient"; + private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes + + FaceGenerateChallengeClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) { + super(context, lazyDaemon, token, listener, owner, sensorId); + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().generateChallenge(mSequentialId, CHALLENGE_TIMEOUT_SEC); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to generateChallenge", e); + } + } + + void onChallengeGenerated(int sensorId, int userId, long challenge) { + try { + getListener().onChallengeGenerated(sensorId, challenge); + mCallback.onClientFinished(this, true /* success */); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send challenge", e); + mCallback.onClientFinished(this, false /* success */); + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java new file mode 100644 index 0000000000000..3280e9815660a --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java @@ -0,0 +1,63 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.ISession; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.ClientMonitor; + +import java.util.Map; + +class FaceGetAuthenticatorIdClient extends ClientMonitor { + + private static final String TAG = "FaceGetAuthenticatorIdClient"; + + private final Map mAuthenticatorIds; + + FaceGetAuthenticatorIdClient(@NonNull Context context, @NonNull LazyDaemon lazyDaemon, + int userId, @NonNull String opPackageName, int sensorId, + Map authenticatorIds) { + super(context, lazyDaemon, null /* token */, null /* listener */, userId, opPackageName, + 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_FACE, + BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); + mAuthenticatorIds = authenticatorIds; + } + + @Override + public void unableToStart() { + // Nothing to do here + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().getAuthenticatorId(mSequentialId); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + } + + void onAuthenticatorIdRetrieved(long authenticatorId) { + mAuthenticatorIds.put(getTargetUserId(), authenticatorId); + mCallback.onClientFinished(this, true /* success */); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java new file mode 100644 index 0000000000000..9680e4e1841e7 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java @@ -0,0 +1,67 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.hardware.face.Face; +import android.os.IBinder; + +import com.android.server.biometrics.sensors.BiometricUtils; +import com.android.server.biometrics.sensors.InternalCleanupClient; +import com.android.server.biometrics.sensors.InternalEnumerateClient; +import com.android.server.biometrics.sensors.RemovalClient; + +import java.util.List; +import java.util.Map; + +/** + * Face-specific internal cleanup client for the {@link IFace} AIDL HAL interface. + */ +class FaceInternalCleanupClient extends InternalCleanupClient { + + FaceInternalCleanupClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, int userId, @NonNull String owner, + int sensorId, @NonNull List enrolledList, @NonNull BiometricUtils utils, + @NonNull Map authenticatorIds) { + super(context, lazyDaemon, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FACE, + enrolledList, utils, authenticatorIds); + } + + @Override + protected InternalEnumerateClient getEnumerateClient(Context context, + LazyDaemon lazyDaemon, IBinder token, int userId, String owner, + List enrolledList, BiometricUtils utils, int sensorId) { + return new FaceInternalEnumerateClient(context, lazyDaemon, token, userId, owner, + enrolledList, utils, sensorId); + } + + @Override + protected RemovalClient getRemovalClient(Context context, + LazyDaemon lazyDaemon, IBinder token, + int biometricId, int userId, String owner, BiometricUtils utils, int sensorId, + Map authenticatorIds) { + // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove) + // is all done internally. + return new FaceRemovalClient(context, lazyDaemon, token, + null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils, + sensorId, authenticatorIds); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java new file mode 100644 index 0000000000000..75888a5f28c94 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java @@ -0,0 +1,57 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.hardware.face.Face; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.BiometricUtils; +import com.android.server.biometrics.sensors.InternalEnumerateClient; + +import java.util.List; + +/** + * Face-specific internal enumerate client for the {@link IFace} AIDL HAL interface. + */ +class FaceInternalEnumerateClient extends InternalEnumerateClient { + private static final String TAG = "FaceInternalEnumerateClient"; + + FaceInternalEnumerateClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, @NonNull IBinder token, int userId, + @NonNull String owner, @NonNull List enrolledList, + @NonNull BiometricUtils utils, int sensorId) { + super(context, lazyDaemon, token, userId, owner, enrolledList, utils, sensorId, + BiometricsProtoEnums.MODALITY_FACE); + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().enumerateEnrollments(mSequentialId); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting enumerate", e); + mCallback.onClientFinished(this, false /* success */); + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java new file mode 100644 index 0000000000000..1cb5031374ec2 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java @@ -0,0 +1,59 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.hardware.face.Face; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.BiometricUtils; +import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; +import com.android.server.biometrics.sensors.RemovalClient; + +import java.util.Map; + +/** + * Face-specific removal client for the {@link IFace} AIDL HAL interface. + */ +class FaceRemovalClient extends RemovalClient { + private static final String TAG = "FaceRemovalClient"; + + FaceRemovalClient(@NonNull Context context, @NonNull LazyDaemon lazyDaemon, + @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, + int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils utils, + int sensorId, @NonNull Map authenticatorIds) { + super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId, + authenticatorIds, BiometricsProtoEnums.MODALITY_FACE); + } + + @Override + protected void startHalOperation() { + try { + final int[] ids = new int[]{mBiometricId}; + getFreshDaemon().removeEnrollments(mSequentialId, ids); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting remove", e); + mCallback.onClientFinished(this, false /* success */); + } + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java new file mode 100644 index 0000000000000..5d100ec5e6dd4 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java @@ -0,0 +1,79 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.BiometricsProtoEnums; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.hardware.keymaster.HardwareAuthToken; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.HardwareAuthTokenUtils; +import com.android.server.biometrics.sensors.ClientMonitor; +import com.android.server.biometrics.sensors.LockoutCache; +import com.android.server.biometrics.sensors.LockoutResetDispatcher; +import com.android.server.biometrics.sensors.LockoutTracker; + +/** + * Face-specific resetLockout client for the {@link IFace} AIDL HAL interface. + * Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is + * cleared. + */ +public class FaceResetLockoutClient extends ClientMonitor { + + private static final String TAG = "FaceResetLockoutClient"; + + private final HardwareAuthToken mHardwareAuthToken; + private final LockoutCache mLockoutCache; + private final LockoutResetDispatcher mLockoutResetDispatcher; + + FaceResetLockoutClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, int userId, String owner, int sensorId, + @NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker, + @NonNull LockoutResetDispatcher lockoutResetDispatcher) { + super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner, + 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, + BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); + mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken); + mLockoutCache = lockoutTracker; + mLockoutResetDispatcher = lockoutResetDispatcher; + } + + @Override + public void unableToStart() { + // Nothing to do here + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().resetLockout(mSequentialId, mHardwareAuthToken); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to reset lockout", e); + mCallback.onClientFinished(this, false /* success */); + } + } + + void onLockoutCleared() { + mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_NONE); + mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId()); + mCallback.onClientFinished(this, true /* success */); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java new file mode 100644 index 0000000000000..2863f9fc2959f --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java @@ -0,0 +1,58 @@ +/* + * 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.aidl; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.ISession; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.RevokeChallengeClient; + +/** + * Face-specific revokeChallenge client for the {@link IFace} AIDL HAL interface. + */ +public class FaceRevokeChallengeClient extends RevokeChallengeClient { + + private static final String TAG = "FaceRevokeChallengeClient"; + + private final long mChallenge; + + FaceRevokeChallengeClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, @NonNull IBinder token, + @NonNull String owner, int sensorId, long challenge) { + super(context, lazyDaemon, token, owner, sensorId); + mChallenge = challenge; + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().revokeChallenge(mSequentialId, mChallenge); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to revokeChallenge", e); + } + } + + void onChallengeRevoked(int sensorId, int userId, long challenge) { + final boolean success = challenge == mChallenge; + mCallback.onClientFinished(this, success); + } +}