diff options
| author | 2021-01-11 13:16:53 -0800 | |
|---|---|---|
| committer | 2021-01-11 16:53:07 -0800 | |
| commit | 775a9a3796fc2c15c4a3b1e438bbea8a9261d98d (patch) | |
| tree | 7e773903122b5cfbd7db4e083d8f3cdd1d4b411f | |
| parent | 259f778bfd760150ad6765b6d16f3450692e6046 (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
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; + } + } +} |