summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kevin Chyn <kchyn@google.com> 2021-01-11 13:16:53 -0800
committer Kevin Chyn <kchyn@google.com> 2021-01-11 16:53:07 -0800
commit775a9a3796fc2c15c4a3b1e438bbea8a9261d98d (patch)
tree7e773903122b5cfbd7db4e083d8f3cdd1d4b411f
parent259f778bfd760150ad6765b6d16f3450692e6046 (diff)
3/n: Add most remaining plumbing for authenticatorId invalidation
1) Adds BiometricManager#invalidateAuthenticatorIds 2) Adds IBiometricAuthenticator#invalidateAuthenticatorId 3) Adds ServiceProvider(s)#invalidateAuthenticatorId 4) Finishes InvalidationRequesterClient implementation A subsequent CL will implement the invalidation plumbing on FaceProvider/FingerprintProvider. Bug: 159667191 Test: atest InvalidationTrackerTest Exempt-From-Owner-Approval: OWNERS not propagated through yet Change-Id: I86eb6a6d37b0d6616422d57c696cd1c9a553847e
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java21
-rw-r--r--core/java/android/hardware/biometrics/IAuthService.aidl6
-rw-r--r--core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl4
-rw-r--r--core/java/android/hardware/biometrics/IBiometricService.aidl6
-rw-r--r--core/java/android/hardware/biometrics/IInvalidationCallback.aidl27
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl4
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl4
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java14
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java77
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java24
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java16
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java11
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java11
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java111
18 files changed, 364 insertions, 8 deletions
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 987d790601b4..4145a7273ed2 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -358,6 +358,27 @@ public class BiometricManager {
}
/**
+ * Requests all {@link Authenticators.Types#BIOMETRIC_STRONG} sensors to have their
+ * authenticatorId invalidated for the specified user. This happens when enrollments have been
+ * added on devices with multiple biometric sensors.
+ *
+ * @param userId userId that the authenticatorId should be invalidated for
+ * @param fromSensorId sensor that triggered the invalidation request
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void invalidateAuthenticatorIds(int userId, int fromSensorId,
+ @NonNull IInvalidationCallback callback) {
+ if (mService != null) {
+ try {
+ mService.invalidateAuthenticatorIds(userId, fromSensorId, callback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Get a list of AuthenticatorIDs for biometric authenticators which have 1) enrolled templates,
* and 2) meet the requirements for integrating with Keystore. The AuthenticatorIDs are known
* in Keystore land as SIDs, and are used during key generation.
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 8e7f5ce8a85d..0dfd5dbf300e 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -18,6 +18,7 @@ package android.hardware.biometrics;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
@@ -57,6 +58,11 @@ interface IAuthService {
// Register callback for when keyguard biometric eligibility changes.
void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
+ // Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the
+ // specified user. This happens when enrollments have been added on devices with multiple
+ // biometric sensors.
+ void invalidateAuthenticatorIds(int userId, int fromSensorId, IInvalidationCallback callback);
+
// Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
// land as SIDs, and are used during key generation.
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index cc12125c13f0..fcdf61e99471 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -18,6 +18,7 @@ package android.hardware.biometrics;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
@@ -63,6 +64,9 @@ interface IBiometricAuthenticator {
// Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int userId);
+ // Request the authenticatorId to be invalidated for the specified user
+ void invalidateAuthenticatorId(int userId, IInvalidationCallback callback);
+
// Gets the authenticator ID representing the current set of enrolled templates
long getAuthenticatorId(int callingUserId);
}
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 6f7bcb68cc8d..a14a910a9e50 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -19,6 +19,7 @@ package android.hardware.biometrics;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricAuthenticator;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
@@ -62,6 +63,11 @@ interface IBiometricService {
// Client lifecycle is still managed in <Biometric>Service.
void onReadyForAuthentication(int cookie);
+ // Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the
+ // specified user. This happens when enrollments have been added on devices with multiple
+ // biometric sensors.
+ void invalidateAuthenticatorIds(int userId, int fromSensorId, IInvalidationCallback callback);
+
// Get a list of AuthenticatorIDs for authenticators which have enrolled templates and meet
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
// land as SIDs, and are used during key generation.
diff --git a/core/java/android/hardware/biometrics/IInvalidationCallback.aidl b/core/java/android/hardware/biometrics/IInvalidationCallback.aidl
new file mode 100644
index 000000000000..24f7d9d7d42e
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IInvalidationCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 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 android.hardware.biometrics;
+
+/**
+ * Notifies the caller for BiometricManager#invalidateAuthenticatorIds status updates. See
+ * InvalidationRequesterClient for more info.
+ * @hide
+ */
+interface IInvalidationCallback {
+ // Notifies the caller when all authenticatorId(s) have been invalidated.
+ void onCompleted();
+} \ No newline at end of file
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 468157a19971..3b19f12a41ba 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -17,6 +17,7 @@ package android.hardware.face;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
@@ -104,6 +105,9 @@ interface IFaceService {
// Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int sensorId, int userId);
+ // Requests for the specified sensor+userId's authenticatorId to be invalidated
+ void invalidateAuthenticatorId(int sensorId, int userId, IInvalidationCallback callback);
+
// Gets the authenticator ID for face
long getAuthenticatorId(int sensorId, int callingUserId);
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index ac026c796b51..74c5b5864e87 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@ package android.hardware.fingerprint;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -116,6 +117,9 @@ interface IFingerprintService {
// Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int sensorId, int userId);
+ // Requests for the specified sensor+userId's authenticatorId to be invalidated
+ void invalidateAuthenticatorId(int sensorId, int userId, IInvalidationCallback callback);
+
// Gets the authenticator ID for fingerprint
long getAuthenticatorId(int sensorId, int callingUserId);
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index cf8bfbc547f8..b15a8869b22a 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -38,6 +38,7 @@ import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
@@ -296,6 +297,19 @@ public class AuthService extends SystemService {
}
@Override
+ public void invalidateAuthenticatorIds(int userId, int fromSensorId,
+ IInvalidationCallback callback) throws RemoteException {
+ checkInternalPermission();
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mBiometricService.invalidateAuthenticatorIds(userId, fromSensorId, callback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public long[] getAuthenticatorIds() throws RemoteException {
// In this method, we're not checking whether the caller is permitted to use face
// API because current authenticator ID is leaked (in a more contrived way) via Android
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a81abcd3b510..fd5ada0ff9be 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -42,6 +42,7 @@ import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricSysuiReceiver;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
@@ -60,6 +61,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.security.KeyStore;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -78,6 +80,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.Set;
/**
* System service that arbitrates the modality for BiometricPrompt to use.
@@ -240,6 +243,72 @@ public class BiometricService extends SystemService {
}
};
+ /**
+ * Tracks authenticatorId invalidation. For more details, see
+ * {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}.
+ */
+ @VisibleForTesting
+ static class InvalidationTracker {
+ @NonNull private final IInvalidationCallback mClientCallback;
+ @NonNull private final Set<Integer> mSensorsPendingInvalidation;
+
+ public static InvalidationTracker start(@NonNull ArrayList<BiometricSensor> sensors,
+ int userId, int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
+ return new InvalidationTracker(sensors, userId, fromSensorId, clientCallback);
+ }
+
+ private InvalidationTracker(@NonNull ArrayList<BiometricSensor> sensors, int userId,
+ int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
+ mClientCallback = clientCallback;
+ mSensorsPendingInvalidation = new ArraySet<>();
+
+ for (BiometricSensor sensor : sensors) {
+ if (sensor.id == fromSensorId) {
+ continue;
+ }
+
+ if (!Utils.isAtLeastStrength(sensor.oemStrength, Authenticators.BIOMETRIC_STRONG)) {
+ continue;
+ }
+
+ Slog.d(TAG, "Requesting authenticatorId invalidation for sensor: " + sensor.id);
+
+ synchronized (this) {
+ mSensorsPendingInvalidation.add(sensor.id);
+ }
+
+ try {
+ sensor.impl.invalidateAuthenticatorId(userId, new IInvalidationCallback.Stub() {
+ @Override
+ public void onCompleted() {
+ onInvalidated(sensor.id);
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.d(TAG, "RemoteException", e);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void onInvalidated(int sensorId) {
+ synchronized (this) {
+ mSensorsPendingInvalidation.remove(sensorId);
+
+ Slog.d(TAG, "Sensor " + sensorId + " invalidated, remaining size: "
+ + mSensorsPendingInvalidation.size());
+
+ if (mSensorsPendingInvalidation.isEmpty()) {
+ try {
+ mClientCallback.onCompleted();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote Exception", e);
+ }
+ }
+ }
+ }
+ }
+
@VisibleForTesting
public static class SettingObserver extends ContentObserver {
@@ -668,6 +737,14 @@ public class BiometricService extends SystemService {
}
}
+ @Override
+ public void invalidateAuthenticatorIds(int userId, int fromSensorId,
+ IInvalidationCallback callback) {
+ checkInternalPermission();
+
+ InvalidationTracker.start(mSensors, userId, fromSensorId, callback);
+ }
+
@Override // Binder call
public long[] getAuthenticatorIds(int callingUserId) {
checkInternalPermission();
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
index ca34eee17f7f..d95fa236fcef 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
@@ -18,8 +18,10 @@ package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IInvalidationCallback;
/**
* ClientMonitor subclass responsible for coordination of authenticatorId invalidation of other
@@ -53,25 +55,39 @@ import android.hardware.biometrics.BiometricsProtoEnums;
* switches, the framework can check if any sensor has the "invalidationInProgress" flag set. If so,
* the framework should re-start the invalidation process described above.
*/
-public abstract class InvalidationRequesterClient<T> extends ClientMonitor<T> {
+public abstract class InvalidationRequesterClient<S extends BiometricAuthenticator.Identifier, T>
+ extends ClientMonitor<T> {
private final BiometricManager mBiometricManager;
+ @NonNull private final BiometricUtils<S> mUtils;
+
+ @NonNull private final IInvalidationCallback mInvalidationCallback =
+ new IInvalidationCallback.Stub() {
+ @Override
+ public void onCompleted() {
+ mUtils.setInvalidationInProgress(getContext(), getTargetUserId(),
+ false /* inProgress */);
+ mCallback.onClientFinished(InvalidationRequesterClient.this, true /* success */);
+ }
+ };
public InvalidationRequesterClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
- int userId, int sensorId) {
+ int userId, int sensorId, @NonNull BiometricUtils<S> utils) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId,
context.getOpPackageName(), 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricManager = context.getSystemService(BiometricManager.class);
+ mUtils = utils;
}
@Override
public void start(@NonNull Callback callback) {
super.start(callback);
- // TODO(b/159667191): Request BiometricManager/BiometricService to invalidate
- // authenticatorIds. Be sure to invoke BiometricUtils#setInvalidationInProgress(true)
+ mUtils.setInvalidationInProgress(getContext(), getTargetUserId(), true /* inProgress */);
+ mBiometricManager.invalidateAuthenticatorIds(getTargetUserId(), getSensorId(),
+ mInvalidationCallback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index f07bf1e236b8..54ab2e564676 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -19,13 +19,13 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.face.IFaceService;
import android.os.IBinder;
import android.os.RemoteException;
-import com.android.server.biometrics.SensorConfig;
import com.android.server.biometrics.sensors.LockoutTracker;
/**
@@ -87,6 +87,12 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
}
@Override
+ public void invalidateAuthenticatorId(int userId, IInvalidationCallback callback)
+ throws RemoteException {
+ mFaceService.invalidateAuthenticatorId(mSensorId, userId, callback);
+ }
+
+ @Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId)
throws RemoteException {
return mFaceService.getLockoutModeForUser(mSensorId, userId);
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 cb56e8cd4b7f..f055d559cc83 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
@@ -29,6 +29,7 @@ import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
@@ -54,10 +55,10 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
-import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.face.aidl.FaceProvider;
import com.android.server.biometrics.sensors.face.hidl.Face10;
@@ -503,6 +504,19 @@ public class FaceService extends SystemService implements BiometricServiceCallba
return provider.getLockoutModeForUser(sensorId, userId);
}
+ @Override
+ public void invalidateAuthenticatorId(int sensorId, int userId,
+ IInvalidationCallback callback) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for invalidateAuthenticatorId");
+ return;
+ }
+ provider.scheduleInvalidateAuthenticatorId(sensorId, userId, callback);
+ }
+
@Override // Binder call
public long getAuthenticatorId(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index be4e2482acc9..51b427d772a1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.face.Face;
import android.hardware.face.FaceManager;
@@ -71,6 +72,16 @@ public interface ServiceProvider {
@LockoutTracker.LockoutMode
int getLockoutModeForUser(int sensorId, int userId);
+ /**
+ * Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to
+ * be invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
+ */
+ default void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
+ @NonNull IInvalidationCallback callback) {
+ throw new IllegalStateException("Providers that support invalidation must override"
+ + " this method");
+ }
+
long getAuthenticatorId(int sensorId, int userId);
boolean isHardwareDetected(int sensorId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index d4cdc8b18898..312a3ba80d69 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -19,13 +19,13 @@ package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintService;
import android.os.IBinder;
import android.os.RemoteException;
-import com.android.server.biometrics.SensorConfig;
import com.android.server.biometrics.sensors.LockoutTracker;
/**
@@ -94,6 +94,12 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
}
@Override
+ public void invalidateAuthenticatorId(int userId, IInvalidationCallback callback)
+ throws RemoteException {
+ mFingerprintService.invalidateAuthenticatorId(mSensorId, userId, callback);
+ }
+
+ @Override
public long getAuthenticatorId(int callingUserId) throws RemoteException {
return mFingerprintService.getAuthenticatorId(mSensorId, callingUserId);
}
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 e6cdbd28f9d1..d541eb3bd176 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
@@ -36,6 +36,7 @@ import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
@@ -571,6 +572,19 @@ public class FingerprintService extends SystemService implements BiometricServic
return provider.getLockoutModeForUser(sensorId, userId);
}
+ @Override
+ public void invalidateAuthenticatorId(int sensorId, int userId,
+ IInvalidationCallback callback) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for invalidateAuthenticatorId");
+ return;
+ }
+ provider.scheduleInvalidateAuthenticatorId(sensorId, userId, callback);
+ }
+
@Override // Binder call
public long getAuthenticatorId(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index d94c98481eeb..272e2b277941 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
@@ -109,6 +110,16 @@ public interface ServiceProvider {
@LockoutTracker.LockoutMode
int getLockoutModeForUser(int sensorId, int userId);
+ /**
+ * Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to
+ * be invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
+ */
+ default void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
+ @NonNull IInvalidationCallback callback) {
+ throw new IllegalStateException("Providers that support invalidation must override"
+ + " this method");
+ }
+
long getAuthenticatorId(int sensorId, int userId);
void onPointerDown(int sensorId, int x, int y, float minor, float major);
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 6f437a7c31d2..3e5b88cca1e4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -19,13 +19,13 @@ package com.android.server.biometrics.sensors.iris;
import android.annotation.NonNull;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.iris.IIrisService;
import android.os.IBinder;
import android.os.RemoteException;
-import com.android.server.biometrics.SensorConfig;
import com.android.server.biometrics.sensors.LockoutTracker;
/**
@@ -86,6 +86,10 @@ public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
}
@Override
+ public void invalidateAuthenticatorId(int userId, IInvalidationCallback callback) {
+ }
+
+ @Override
public long getAuthenticatorId(int callingUserId) throws RemoteException {
return 0;
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java
new file mode 100644
index 000000000000..340a1d9bdda0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/InvalidationTrackerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.IBiometricAuthenticator;
+import android.hardware.biometrics.IInvalidationCallback;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.biometrics.BiometricService.InvalidationTracker;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+@Presubmit
+@SmallTest
+public class InvalidationTrackerTest {
+
+ @Test
+ public void testCallbackReceived_whenAllStrongSensorsInvalidated() throws Exception {
+ final IBiometricAuthenticator authenticator1 = mock(IBiometricAuthenticator.class);
+ final TestSensor sensor1 = new TestSensor(0 /* id */,
+ BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG,
+ authenticator1);
+
+ final IBiometricAuthenticator authenticator2 = mock(IBiometricAuthenticator.class);
+ final TestSensor sensor2 = new TestSensor(1 /* id */,
+ BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG,
+ authenticator2);
+
+ final IBiometricAuthenticator authenticator3 = mock(IBiometricAuthenticator.class);
+ final TestSensor sensor3 = new TestSensor(2 /* id */,
+ BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG,
+ authenticator3);
+
+ final IBiometricAuthenticator authenticator4 = mock(IBiometricAuthenticator.class);
+ final TestSensor sensor4 = new TestSensor(3 /* id */,
+ BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK,
+ authenticator4);
+
+ final ArrayList<BiometricSensor> sensors = new ArrayList<>();
+ sensors.add(sensor1);
+ sensors.add(sensor2);
+ sensors.add(sensor3);
+ sensors.add(sensor4);
+
+ final IInvalidationCallback callback = mock(IInvalidationCallback.class);
+ final InvalidationTracker tracker =
+ InvalidationTracker.start(sensors, 0 /* userId */, 0 /* fromSensorId */, callback);
+
+ // The sensor which the request originated from should not be requested to invalidate
+ // its authenticatorId.
+ verify(authenticator1, never()).invalidateAuthenticatorId(anyInt(), any());
+
+ // All other strong sensors should be requested to invalidate authenticatorId
+ verify(authenticator2).invalidateAuthenticatorId(eq(0) /* userId */, any());
+ verify(authenticator3).invalidateAuthenticatorId(eq(0) /* userId */, any());
+
+ // Weak sensors are not requested to invalidate authenticatorId
+ verify(authenticator4, never()).invalidateAuthenticatorId(anyInt(), any());
+
+ // Client is not notified until invalidation for all required sensors have completed
+ verify(callback, never()).onCompleted();
+ tracker.onInvalidated(1);
+ verify(callback, never()).onCompleted();
+ tracker.onInvalidated(2);
+ verify(callback).onCompleted();
+ }
+
+ private static class TestSensor extends BiometricSensor {
+
+ TestSensor(int id, int modality, int strength, IBiometricAuthenticator impl) {
+ super(id, modality, strength, impl);
+ }
+
+ @Override
+ boolean confirmationAlwaysRequired(int userId) {
+ return false;
+ }
+
+ @Override
+ boolean confirmationSupported() {
+ return false;
+ }
+ }
+}