summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java20
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricContext.java7
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java86
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java166
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthSessionListener.java19
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java164
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java48
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java21
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java101
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java69
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java164
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java6
21 files changed, 697 insertions, 244 deletions
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 3f139f02efaf..2eb8cb9f2f81 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -212,6 +212,26 @@ public class BiometricManager {
* @see android.security.keystore.KeyGenParameterSpec.Builder
*/
int DEVICE_CREDENTIAL = 1 << 15;
+
+ }
+
+ /**
+ * @hide
+ * returns a string representation of an authenticator type.
+ */
+ @NonNull public static String authenticatorToStr(@Authenticators.Types int authenticatorType) {
+ switch(authenticatorType) {
+ case Authenticators.BIOMETRIC_STRONG:
+ return "BIOMETRIC_STRONG";
+ case Authenticators.BIOMETRIC_WEAK:
+ return "BIOMETRIC_WEAK";
+ case Authenticators.BIOMETRIC_CONVENIENCE:
+ return "BIOMETRIC_CONVENIENCE";
+ case Authenticators.DEVICE_CREDENTIAL:
+ return "DEVICE_CREDENTIAL";
+ default:
+ return "Unknown authenticator type: " + authenticatorType;
+ }
}
/**
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContext.java b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
index 8265203ddacd..be04364dcff3 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContext.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
@@ -21,11 +21,15 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.common.OperationContext;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
+
import java.util.function.Consumer;
/**
* Cache for system state not directly related to biometric operations that is used for
* logging or optimizations.
+ *
+ * This class is also used to inject dependencies such as {@link AuthSessionCoordinator}
*/
public interface BiometricContext {
/** Gets the context source from the system context. */
@@ -59,4 +63,7 @@ public interface BiometricContext {
/** Unsubscribe from context changes. */
void unsubscribe(@NonNull OperationContext context);
+
+ /** Obtains an AuthSessionCoordinator. */
+ AuthSessionCoordinator getAuthSessionCoordinator();
}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
index 3d1a6343cbf2..23b2714dd50b 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
@@ -35,6 +35,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.internal.statusbar.ISessionListener;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -59,7 +60,8 @@ final class BiometricContextProvider implements BiometricContext {
sInstance = new BiometricContextProvider(
new AmbientDisplayConfiguration(context),
IStatusBarService.Stub.asInterface(ServiceManager.getServiceOrThrow(
- Context.STATUS_BAR_SERVICE)), null /* handler */);
+ Context.STATUS_BAR_SERVICE)), null /* handler */,
+ new AuthSessionCoordinator());
} catch (ServiceNotFoundException e) {
throw new IllegalStateException("Failed to find required service", e);
}
@@ -76,13 +78,16 @@ final class BiometricContextProvider implements BiometricContext {
private final Map<Integer, InstanceId> mSession = new ConcurrentHashMap<>();
private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+ private final AuthSessionCoordinator mAuthSessionCoordinator;
private boolean mIsAod = false;
private boolean mIsAwake = false;
@VisibleForTesting
BiometricContextProvider(@NonNull AmbientDisplayConfiguration ambientDisplayConfiguration,
- @NonNull IStatusBarService service, @Nullable Handler handler) {
+ @NonNull IStatusBarService service, @Nullable Handler handler,
+ AuthSessionCoordinator authSessionCoordinator) {
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
+ mAuthSessionCoordinator = authSessionCoordinator;
try {
service.setBiometicContextListener(new IBiometricContextListener.Stub() {
@Override
@@ -190,6 +195,11 @@ final class BiometricContextProvider implements BiometricContext {
mSubscribers.remove(context);
}
+ @Override
+ public AuthSessionCoordinator getAuthSessionCoordinator() {
+ return mAuthSessionCoordinator;
+ }
+
private void notifySubscribers() {
mSubscribers.forEach((context, consumer) -> {
context.isAod = isAod();
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java
index 6d00c3fc15ea..bdae5f3eac32 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java
@@ -17,9 +17,11 @@
package com.android.server.biometrics.sensors;
import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.util.ArrayMap;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collections;
+import java.util.Map;
+import java.util.function.IntFunction;
/**
* A class that takes in a series of authentication attempts (successes, failures, lockouts)
@@ -30,64 +32,64 @@ import java.util.List;
*/
class AuthResultCoordinator {
+ /**
+ * Indicates no change has occurred with this authenticator.
+ */
+ static final int AUTHENTICATOR_DEFAULT = 0;
+ /**
+ * Indicated this authenticator has received a lockout.
+ */
+ static final int AUTHENTICATOR_LOCKED = 1 << 0;
+ /**
+ * Indicates this authenticator has received a successful unlock.
+ */
+ static final int AUTHENTICATOR_UNLOCKED = 1 << 1;
private static final String TAG = "AuthResultCoordinator";
- private final List<AuthResult> mOperations;
+ private final Map<Integer, Integer> mAuthenticatorState;
AuthResultCoordinator() {
- mOperations = new ArrayList<>();
+ mAuthenticatorState = new ArrayMap<>();
+ mAuthenticatorState.put(Authenticators.BIOMETRIC_STRONG, AUTHENTICATOR_DEFAULT);
+ mAuthenticatorState.put(Authenticators.BIOMETRIC_WEAK, AUTHENTICATOR_DEFAULT);
+ mAuthenticatorState.put(Authenticators.BIOMETRIC_CONVENIENCE, AUTHENTICATOR_DEFAULT);
}
- /**
- * Adds auth success for a given strength to the current operation list.
- */
- void authenticatedFor(@Authenticators.Types int strength) {
- mOperations.add(new AuthResult(AuthResult.AUTHENTICATED, strength));
+ private void updateState(@Authenticators.Types int strength, IntFunction<Integer> mapper) {
+ switch (strength) {
+ case Authenticators.BIOMETRIC_STRONG:
+ mAuthenticatorState.put(Authenticators.BIOMETRIC_STRONG,
+ mapper.apply(mAuthenticatorState.get(Authenticators.BIOMETRIC_STRONG)));
+ // fall through
+ case Authenticators.BIOMETRIC_WEAK:
+ mAuthenticatorState.put(Authenticators.BIOMETRIC_WEAK,
+ mapper.apply(mAuthenticatorState.get(Authenticators.BIOMETRIC_WEAK)));
+ // fall through
+ case Authenticators.BIOMETRIC_CONVENIENCE:
+ mAuthenticatorState.put(Authenticators.BIOMETRIC_CONVENIENCE,
+ mapper.apply(
+ mAuthenticatorState.get(Authenticators.BIOMETRIC_CONVENIENCE)));
+ }
}
/**
- * Adds auth ended for a given strength to the current operation list.
+ * Adds auth success for a given strength to the current operation list.
*/
- void authEndedFor(@Authenticators.Types int strength) {
- mOperations.add(new AuthResult(AuthResult.FAILED, strength));
+ void authenticatedFor(@Authenticators.Types int strength) {
+ updateState(strength, (old) -> AUTHENTICATOR_UNLOCKED | old);
}
/**
* Adds a lock out of a given strength to the current operation list.
*/
void lockedOutFor(@Authenticators.Types int strength) {
- mOperations.add(new AuthResult(AuthResult.LOCKED_OUT, strength));
+ updateState(strength, (old) -> AUTHENTICATOR_LOCKED | old);
}
/**
- * Obtains an auth result & strength from a current set of biometric operations.
+ * Returns the current authenticator state. Each authenticator will have
+ * the associated operations that were performed on them(DEFAULT, LOCKED, UNLOCKED).
*/
- AuthResult getResult() {
- AuthResult result = new AuthResult(AuthResult.FAILED, Authenticators.BIOMETRIC_CONVENIENCE);
- return mOperations.stream().filter(
- (element) -> element.getStatus() != AuthResult.FAILED).reduce(result,
- ((curr, next) -> {
- int strengthCompare = curr.getBiometricStrength() - next.getBiometricStrength();
- if (strengthCompare < 0) {
- return curr;
- } else if (strengthCompare == 0) {
- // Equal level of strength, favor authentication.
- if (curr.getStatus() == AuthResult.AUTHENTICATED) {
- return curr;
- } else {
- // Either next is Authenticated, or it is not, either way return this
- // one.
- return next;
- }
- } else {
- // curr is a weaker biometric
- return next;
- }
- }));
- }
-
- void resetState() {
- mOperations.clear();
+ final Map<Integer, Integer> getResult() {
+ return Collections.unmodifiableMap(mAuthenticatorState);
}
}
-
-
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
index 13840ff389d9..dec1b559556a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
@@ -16,10 +16,22 @@
package com.android.server.biometrics.sensors;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_LOCKED;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_UNLOCKED;
+
import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.os.SystemClock;
+import android.util.Pair;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.time.Clock;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -28,20 +40,31 @@ import java.util.Set;
* This class is not thread-safe. In general, all calls to this class should be made on the same
* handler to ensure no collisions.
*/
-class AuthSessionCoordinator implements AuthSessionListener {
+public class AuthSessionCoordinator implements AuthSessionListener {
private static final String TAG = "AuthSessionCoordinator";
private final Set<Integer> mAuthOperations;
+ private final MultiBiometricLockoutState mMultiBiometricLockoutState;
+ private final List<Pair<Integer, Long>> mTimedLockouts;
+ private final RingBuffer mRingBuffer;
+ private final Clock mClock;
private int mUserId;
private boolean mIsAuthenticating;
private AuthResultCoordinator mAuthResultCoordinator;
- private MultiBiometricLockoutState mMultiBiometricLockoutState;
- AuthSessionCoordinator() {
+ public AuthSessionCoordinator() {
+ this(SystemClock.currentNetworkTimeClock());
+ }
+
+ @VisibleForTesting
+ AuthSessionCoordinator(Clock clock) {
mAuthOperations = new HashSet<>();
mAuthResultCoordinator = new AuthResultCoordinator();
- mMultiBiometricLockoutState = new MultiBiometricLockoutState();
+ mMultiBiometricLockoutState = new MultiBiometricLockoutState(clock);
+ mRingBuffer = new RingBuffer(100);
+ mTimedLockouts = new ArrayList<>();
+ mClock = clock;
}
/**
@@ -51,7 +74,9 @@ class AuthSessionCoordinator implements AuthSessionListener {
mAuthOperations.clear();
mUserId = userId;
mIsAuthenticating = true;
- mAuthResultCoordinator.resetState();
+ mAuthOperations.clear();
+ mAuthResultCoordinator = new AuthResultCoordinator();
+ mRingBuffer.addApiCall("internal : onAuthSessionStarted(" + userId + ")");
}
/**
@@ -64,14 +89,27 @@ class AuthSessionCoordinator implements AuthSessionListener {
void endAuthSession() {
if (mIsAuthenticating) {
mAuthOperations.clear();
- AuthResult res =
- mAuthResultCoordinator.getResult();
- if (res.getStatus() == AuthResult.AUTHENTICATED) {
- mMultiBiometricLockoutState.onUserUnlocked(mUserId, res.getBiometricStrength());
- } else if (res.getStatus() == AuthResult.LOCKED_OUT) {
- mMultiBiometricLockoutState.onUserLocked(mUserId, res.getBiometricStrength());
+ final long currentTime = mClock.millis();
+ for (Pair<Integer, Long> timedLockouts : mTimedLockouts) {
+ mMultiBiometricLockoutState.increaseLockoutTime(mUserId, timedLockouts.first,
+ timedLockouts.second + currentTime);
+ }
+ // User unlocks can also unlock timed lockout Authenticator.Types
+ final Map<Integer, Integer> result = mAuthResultCoordinator.getResult();
+ for (int authenticator : Arrays.asList(Authenticators.BIOMETRIC_CONVENIENCE,
+ Authenticators.BIOMETRIC_WEAK, Authenticators.BIOMETRIC_STRONG)) {
+ final Integer value = result.get(authenticator);
+ if ((value & AUTHENTICATOR_UNLOCKED) == AUTHENTICATOR_UNLOCKED) {
+ mMultiBiometricLockoutState.setAuthenticatorTo(mUserId, authenticator,
+ true /* canAuthenticate */);
+ mMultiBiometricLockoutState.clearLockoutTime(mUserId, authenticator);
+ } else if ((value & AUTHENTICATOR_LOCKED) == AUTHENTICATOR_LOCKED) {
+ mMultiBiometricLockoutState.setAuthenticatorTo(mUserId, authenticator,
+ false /* canAuthenticate */);
+ }
+
}
- mAuthResultCoordinator.resetState();
+ mRingBuffer.addApiCall("internal : onAuthSessionEnded(" + mUserId + ")");
mIsAuthenticating = false;
}
}
@@ -79,12 +117,15 @@ class AuthSessionCoordinator implements AuthSessionListener {
/**
* @return true if a user can authenticate with a given strength.
*/
- boolean getCanAuthFor(int userId, @Authenticators.Types int strength) {
+ public boolean getCanAuthFor(int userId, @Authenticators.Types int strength) {
return mMultiBiometricLockoutState.canUserAuthenticate(userId, strength);
}
@Override
- public void authStartedFor(int userId, int sensorId) {
+ public void authStartedFor(int userId, int sensorId, long requestId) {
+ mRingBuffer.addApiCall(
+ "authStartedFor(userId=" + userId + ", sensorId=" + sensorId + ", requestId="
+ + requestId + ")");
if (!mIsAuthenticating) {
onAuthSessionStarted(userId);
}
@@ -105,34 +146,58 @@ class AuthSessionCoordinator implements AuthSessionListener {
@Override
public void authenticatedFor(int userId, @Authenticators.Types int biometricStrength,
- int sensorId) {
+ int sensorId, long requestId) {
+ final String authStr =
+ "authenticatedFor(userId=" + userId + ", strength=" + biometricStrength
+ + " , sensorId=" + sensorId + ", requestId= " + requestId + ")";
+ mRingBuffer.addApiCall(authStr);
mAuthResultCoordinator.authenticatedFor(biometricStrength);
- attemptToFinish(userId, sensorId,
- "authenticatedFor(userId=" + userId + ", biometricStrength=" + biometricStrength
- + ", sensorId=" + sensorId + "");
+ attemptToFinish(userId, sensorId, authStr);
}
@Override
public void lockedOutFor(int userId, @Authenticators.Types int biometricStrength,
- int sensorId) {
- mAuthResultCoordinator.lockedOutFor(biometricStrength);
- attemptToFinish(userId, sensorId,
+ int sensorId, long requestId) {
+ final String lockedOutStr =
"lockOutFor(userId=" + userId + ", biometricStrength=" + biometricStrength
- + ", sensorId=" + sensorId + "");
+ + ", sensorId=" + sensorId + ", requestId=" + requestId + ")";
+ mRingBuffer.addApiCall(lockedOutStr);
+ mAuthResultCoordinator.lockedOutFor(biometricStrength);
+ attemptToFinish(userId, sensorId, lockedOutStr);
+ }
+
+ @Override
+ public void lockOutTimed(int userId, @Authenticators.Types int biometricStrength, int sensorId,
+ long time, long requestId) {
+ final String lockedOutStr =
+ "lockOutTimedFor(userId=" + userId + ", biometricStrength=" + biometricStrength
+ + ", sensorId=" + sensorId + "time=" + time + ", requestId=" + requestId
+ + ")";
+ mRingBuffer.addApiCall(lockedOutStr);
+ mTimedLockouts.add(new Pair<>(biometricStrength, time));
+ attemptToFinish(userId, sensorId, lockedOutStr);
}
@Override
public void authEndedFor(int userId, @Authenticators.Types int biometricStrength,
- int sensorId) {
- mAuthResultCoordinator.authEndedFor(biometricStrength);
- attemptToFinish(userId, sensorId,
+ int sensorId, long requestId) {
+ final String authEndedStr =
"authEndedFor(userId=" + userId + " ,biometricStrength=" + biometricStrength
- + ", sensorId=" + sensorId);
+ + ", sensorId=" + sensorId + ", requestId=" + requestId + ")";
+ mRingBuffer.addApiCall(authEndedStr);
+ attemptToFinish(userId, sensorId, authEndedStr);
}
@Override
- public void resetLockoutFor(int userId, @Authenticators.Types int biometricStrength) {
- mMultiBiometricLockoutState.onUserUnlocked(userId, biometricStrength);
+ public void resetLockoutFor(int userId, @Authenticators.Types int biometricStrength,
+ long requestId) {
+ final String resetLockStr =
+ "resetLockoutFor(userId=" + userId + " ,biometricStrength=" + biometricStrength
+ + ", requestId=" + requestId + ")";
+ mRingBuffer.addApiCall(resetLockStr);
+ mMultiBiometricLockoutState.setAuthenticatorTo(userId, biometricStrength,
+ true /*canAuthenticate */);
+ mMultiBiometricLockoutState.clearLockoutTime(userId, biometricStrength);
}
private void attemptToFinish(int userId, int sensorId, String description) {
@@ -154,4 +219,49 @@ class AuthSessionCoordinator implements AuthSessionListener {
}
}
+ /**
+ * Returns a string representation of the past N API calls as well as the
+ * permanent and timed lockout states for each user's authenticators.
+ */
+ @Override
+ public String toString() {
+ return mRingBuffer + "\n" + mMultiBiometricLockoutState;
+ }
+
+ private static class RingBuffer {
+ private final String[] mApiCalls;
+ private final int mSize;
+ private int mCurr;
+ private int mApiCallNumber;
+
+ RingBuffer(int size) {
+ if (size <= 0) {
+ Slog.wtf(TAG, "Cannot initialize ring buffer of size: " + size);
+ }
+ mApiCalls = new String[size];
+ mCurr = 0;
+ mSize = size;
+ mApiCallNumber = 0;
+ }
+
+ void addApiCall(String str) {
+ mApiCalls[mCurr] = str;
+ mCurr++;
+ mCurr %= mSize;
+ mApiCallNumber++;
+ }
+
+ @Override
+ public String toString() {
+ String buffer = "";
+ int apiCall = mApiCallNumber > mSize ? mApiCallNumber - mSize : 0;
+ for (int i = 0; i < mSize; i++) {
+ final int location = (mCurr + i) % mSize;
+ if (mApiCalls[location] != null) {
+ buffer += String.format("#%-5d %s\n", apiCall++, mApiCalls[location]);
+ }
+ }
+ return buffer;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthSessionListener.java b/services/core/java/com/android/server/biometrics/sensors/AuthSessionListener.java
index 8b1f90af0234..d97f793a84bc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthSessionListener.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthSessionListener.java
@@ -25,25 +25,34 @@ interface AuthSessionListener {
/**
* Indicates an auth operation has started for a given user and sensor.
*/
- void authStartedFor(int userId, int sensorId);
+ void authStartedFor(int userId, int sensorId, long requestId);
/**
* Indicates a successful authentication occurred for a sensor of a given strength.
*/
- void authenticatedFor(int userId, @Authenticators.Types int biometricStrength, int sensorId);
+ void authenticatedFor(int userId, @Authenticators.Types int biometricStrength, int sensorId,
+ long requestId);
/**
* Indicates authentication ended for a sensor of a given strength.
*/
- void authEndedFor(int userId, @Authenticators.Types int biometricStrength, int sensorId);
+ void authEndedFor(int userId, @Authenticators.Types int biometricStrength, int sensorId,
+ long requestId);
/**
* Indicates a lockout occurred for a sensor of a given strength.
*/
- void lockedOutFor(int userId, @Authenticators.Types int biometricStrength, int sensorId);
+ void lockedOutFor(int userId, @Authenticators.Types int biometricStrength, int sensorId,
+ long requestId);
+
+ /**
+ * Indicates a timed lockout occurred for a sensor of a given strength.
+ */
+ void lockOutTimed(int userId, @Authenticators.Types int biometricStrength, int sensorId,
+ long duration, long requestId);
/**
* Indicates that a reset lockout has happened for a given strength.
*/
- void resetLockoutFor(int uerId, @Authenticators.Types int biometricStrength);
+ void resetLockoutFor(int uerId, @Authenticators.Types int biometricStrength, long requestId);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java b/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java
index 49dc817c7fd5..d9bd04d3f1c8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java
@@ -21,82 +21,93 @@ import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMET
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK;
-import android.util.ArrayMap;
+import android.hardware.biometrics.BiometricManager;
+import android.os.SystemClock;
import android.util.Slog;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Arrays;
-import java.util.Collections;
+import java.time.Clock;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
/**
* This class is used as a system to store the state of each
* {@link Authenticators.Types} status for every user.
+ *
+ * Note that initially all biomertics are unlocked, meaning users can authenticate
+ * with each strength.
*/
class MultiBiometricLockoutState {
private static final String TAG = "MultiBiometricLockoutState";
- private static final Map<Integer, List<Integer>> PRECEDENCE;
-
- static {
- Map<Integer, List<Integer>> precedence = new ArrayMap<>();
- precedence.put(Authenticators.BIOMETRIC_STRONG,
- Arrays.asList(BIOMETRIC_STRONG, BIOMETRIC_WEAK, BIOMETRIC_CONVENIENCE));
- precedence.put(BIOMETRIC_WEAK, Arrays.asList(BIOMETRIC_WEAK, BIOMETRIC_CONVENIENCE));
- precedence.put(BIOMETRIC_CONVENIENCE, Arrays.asList(BIOMETRIC_CONVENIENCE));
- PRECEDENCE = Collections.unmodifiableMap(precedence);
- }
-
- private final Map<Integer, Map<Integer, Boolean>> mCanUserAuthenticate;
+ private final Map<Integer, Map<Integer, AuthenticatorState>> mCanUserAuthenticate;
+ private final Clock mClock;
- @VisibleForTesting
MultiBiometricLockoutState() {
+ this(SystemClock.currentNetworkTimeClock());
+ }
+
+ MultiBiometricLockoutState(Clock clock) {
mCanUserAuthenticate = new HashMap<>();
+ mClock = clock;
}
- private static Map<Integer, Boolean> createLockedOutMap() {
- Map<Integer, Boolean> lockOutMap = new HashMap<>();
- lockOutMap.put(BIOMETRIC_STRONG, false);
- lockOutMap.put(BIOMETRIC_WEAK, false);
- lockOutMap.put(BIOMETRIC_CONVENIENCE, false);
+ private Map<Integer, AuthenticatorState> createUnlockedMap() {
+ Map<Integer, AuthenticatorState> lockOutMap = new HashMap<>();
+ lockOutMap.put(BIOMETRIC_STRONG,
+ new AuthenticatorState(BIOMETRIC_STRONG, false, 0, mClock));
+ lockOutMap.put(BIOMETRIC_WEAK, new AuthenticatorState(BIOMETRIC_WEAK, false, 0, mClock));
+ lockOutMap.put(BIOMETRIC_CONVENIENCE,
+ new AuthenticatorState(BIOMETRIC_CONVENIENCE, false, 0, mClock));
return lockOutMap;
}
- private Map<Integer, Boolean> getAuthMapForUser(int userId) {
+ private Map<Integer, AuthenticatorState> getAuthMapForUser(int userId) {
if (!mCanUserAuthenticate.containsKey(userId)) {
- mCanUserAuthenticate.put(userId, createLockedOutMap());
+ mCanUserAuthenticate.put(userId, createUnlockedMap());
}
return mCanUserAuthenticate.get(userId);
}
- /**
- * Indicates a {@link Authenticators} has been locked for userId.
- *
- * @param userId The user.
- * @param strength The strength of biometric that is requested to be locked.
- */
- void onUserLocked(int userId, @Authenticators.Types int strength) {
- Slog.d(TAG, "onUserLocked(userId=" + userId + ", strength=" + strength + ")");
- Map<Integer, Boolean> canUserAuthState = getAuthMapForUser(userId);
- for (int strengthToLockout : PRECEDENCE.get(strength)) {
- canUserAuthState.put(strengthToLockout, false);
+ void setAuthenticatorTo(int userId, @Authenticators.Types int strength, boolean canAuth) {
+ final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
+ switch (strength) {
+ case Authenticators.BIOMETRIC_STRONG:
+ authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = !canAuth;
+ // fall through
+ case Authenticators.BIOMETRIC_WEAK:
+ authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = !canAuth;
+ // fall through
+ case Authenticators.BIOMETRIC_CONVENIENCE:
+ authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = !canAuth;
}
}
- /**
- * Indicates that a user has unlocked a {@link Authenticators}
- *
- * @param userId The user.
- * @param strength The strength of biometric that is unlocked.
- */
- void onUserUnlocked(int userId, @Authenticators.Types int strength) {
- Slog.d(TAG, "onUserUnlocked(userId=" + userId + ", strength=" + strength + ")");
- Map<Integer, Boolean> canUserAuthState = getAuthMapForUser(userId);
- for (int strengthToLockout : PRECEDENCE.get(strength)) {
- canUserAuthState.put(strengthToLockout, true);
+ void increaseLockoutTime(int userId, @Authenticators.Types int strength, long duration) {
+ final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
+ switch (strength) {
+ case Authenticators.BIOMETRIC_STRONG:
+ authMap.get(BIOMETRIC_STRONG).increaseLockoutTo(duration);
+ // fall through
+ case Authenticators.BIOMETRIC_WEAK:
+ authMap.get(BIOMETRIC_WEAK).increaseLockoutTo(duration);
+ // fall through
+ case Authenticators.BIOMETRIC_CONVENIENCE:
+ authMap.get(BIOMETRIC_CONVENIENCE).increaseLockoutTo(duration);
+ }
+ }
+
+ void clearLockoutTime(int userId, @Authenticators.Types int strength) {
+ final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
+ switch (strength) {
+ case Authenticators.BIOMETRIC_STRONG:
+ authMap.get(BIOMETRIC_STRONG).setTimedLockout(0);
+ // fall through
+ case Authenticators.BIOMETRIC_WEAK:
+ authMap.get(BIOMETRIC_WEAK).setTimedLockout(0);
+ // fall through
+ case Authenticators.BIOMETRIC_CONVENIENCE:
+ authMap.get(BIOMETRIC_CONVENIENCE).setTimedLockout(0);
}
}
@@ -109,9 +120,64 @@ class MultiBiometricLockoutState {
* @return If a user can authenticate with a given biometric of this strength.
*/
boolean canUserAuthenticate(int userId, @Authenticators.Types int strength) {
- final boolean canAuthenticate = getAuthMapForUser(userId).get(strength);
+ final boolean canAuthenticate = getAuthMapForUser(userId).get(strength).canAuthenticate();
Slog.d(TAG, "canUserAuthenticate(userId=" + userId + ", strength=" + strength + ") ="
+ canAuthenticate);
return canAuthenticate;
}
+
+ @Override
+ public String toString() {
+ String dumpState = "Permanent Lockouts\n";
+ final long time = mClock.millis();
+ for (Map.Entry<Integer, Map<Integer, AuthenticatorState>> userState :
+ mCanUserAuthenticate.entrySet()) {
+ final int userId = userState.getKey();
+ final Map<Integer, AuthenticatorState> map = userState.getValue();
+ String prettyStr = map.entrySet().stream().map(
+ (Map.Entry<Integer, AuthenticatorState> entry) -> entry.getValue().toString(
+ time)).collect(Collectors.joining(", "));
+ dumpState += "UserId=" + userId + ", {" + prettyStr + "}\n";
+ }
+ return dumpState;
+ }
+
+ private static class AuthenticatorState {
+ private Integer mAuthenticatorType;
+ private boolean mPermanentlyLockedOut;
+ private long mTimedLockout;
+ private Clock mClock;
+
+ AuthenticatorState(Integer authenticatorId, boolean permanentlyLockedOut,
+ long timedLockout, Clock clock) {
+ mAuthenticatorType = authenticatorId;
+ mPermanentlyLockedOut = permanentlyLockedOut;
+ mTimedLockout = timedLockout;
+ mClock = clock;
+ }
+
+ boolean canAuthenticate() {
+ return !mPermanentlyLockedOut && mClock.millis() - mTimedLockout >= 0;
+ }
+
+ /**
+ * Either increases the lockout to duration, or leaves it as it, whichever is longer.
+ */
+ void increaseLockoutTo(long duration) {
+ mTimedLockout = Math.max(mTimedLockout, duration);
+ }
+
+ void setTimedLockout(long duration) {
+ mTimedLockout = duration;
+ }
+
+ String toString(long currentTime) {
+ final String duration =
+ mTimedLockout - currentTime > 0 ? (mTimedLockout - currentTime) + "ms" : "none";
+ final String permanentLockout = mPermanentlyLockedOut ? "true" : "false";
+ return String.format("(%s, permanentLockout=%s, timedLockoutRemaining=%s)",
+ BiometricManager.authenticatorToStr(mAuthenticatorType), permanentLockout,
+ duration);
+ }
+ }
}
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
index 2e4c32340320..c27d71f2f079 100644
--- 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
@@ -25,6 +25,7 @@ import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.face.IFace;
import android.hardware.face.FaceAuthenticationFrame;
@@ -38,6 +39,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -58,18 +60,25 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
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;
- @Nullable private SensorPrivacyManager mSensorPrivacyManager;
-
+ @NonNull
+ private final UsageStats mUsageStats;
+ @NonNull
+ private final LockoutCache mLockoutCache;
+ @NonNull
+ private final AuthSessionCoordinator mAuthSessionCoordinator;
+ @Nullable
+ private final NotificationManager mNotificationManager;
private final int[] mBiometricPromptIgnoreList;
private final int[] mBiometricPromptIgnoreListVendor;
private final int[] mKeyguardIgnoreList;
private final int[] mKeyguardIgnoreListVendor;
-
- @FaceManager.FaceAcquired private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN;
+ private final int mBiometricStrength;
+ @Nullable
+ private ICancellationSignal mCancellationSignal;
+ @Nullable
+ private SensorPrivacyManager mSensorPrivacyManager;
+ @FaceManager.FaceAcquired
+ private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN;
FaceAuthenticationClient(@NonNull Context context,
@NonNull Supplier<AidlSession> lazyDaemon,
@@ -79,11 +88,12 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @NonNull UsageStats usageStats,
@NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
- boolean isKeyguardBypassEnabled) {
+ boolean isKeyguardBypassEnabled, @Authenticators.Types int biometricStrength) {
this(context, lazyDaemon, token, requestId, listener, targetUserId, operationId,
restricted, owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, usageStats, lockoutCache, allowBackgroundAuthentication,
- isKeyguardBypassEnabled, context.getSystemService(SensorPrivacyManager.class));
+ isKeyguardBypassEnabled, context.getSystemService(SensorPrivacyManager.class),
+ biometricStrength);
}
@VisibleForTesting
@@ -95,7 +105,8 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
boolean isStrongBiometric, @NonNull UsageStats usageStats,
@NonNull LockoutCache lockoutCache, boolean allowBackgroundAuthentication,
- boolean isKeyguardBypassEnabled, SensorPrivacyManager sensorPrivacyManager) {
+ boolean isKeyguardBypassEnabled, SensorPrivacyManager sensorPrivacyManager,
+ @Authenticators.Types int biometricStrength) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
isStrongBiometric, null /* taskStackListener */, lockoutCache,
@@ -107,6 +118,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);
mSensorPrivacyManager = sensorPrivacyManager;
+ mAuthSessionCoordinator = biometricContext.getAuthSessionCoordinator();
final Resources resources = getContext().getResources();
mBiometricPromptIgnoreList = resources.getIntArray(
@@ -117,12 +129,14 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
R.array.config_face_acquire_keyguard_ignorelist);
mKeyguardIgnoreListVendor = resources.getIntArray(
R.array.config_face_acquire_vendor_keyguard_ignorelist);
+ mBiometricStrength = biometricStrength;
}
@Override
public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
mState = STATE_STARTED;
+ mAuthSessionCoordinator.authStartedFor(getTargetUserId(), getSensorId(), getRequestId());
}
@NonNull
@@ -138,7 +152,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
.isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
- SensorPrivacyManager.Sensors.CAMERA)) {
+ SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
@@ -207,6 +221,9 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
0 /* error */,
0 /* vendorError */,
getTargetUserId()));
+ mAuthSessionCoordinator
+ .authenticatedFor(getTargetUserId(), mBiometricStrength, getSensorId(),
+ getRequestId());
}
@Override
@@ -222,7 +239,8 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
if (error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL) {
BiometricNotificationUtils.showReEnrollmentNotification(getContext());
}
-
+ mAuthSessionCoordinator.authEndedFor(getTargetUserId(), mBiometricStrength, getSensorId(),
+ getRequestId());
super.onError(error, vendorCode);
}
@@ -283,6 +301,8 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
+ mAuthSessionCoordinator.lockOutTimed(getTargetUserId(), mBiometricStrength, getSensorId(),
+ durationMillis, getRequestId());
}
@Override
@@ -298,5 +318,7 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
+ mAuthSessionCoordinator.lockedOutFor(getTargetUserId(), mBiometricStrength, getSensorId(),
+ getRequestId());
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 6bff179e8eb7..b60f9d80d425 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -414,6 +414,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
+ final int biometricStrength = Utils.getCurrentStrength(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
userId, operationId, restricted, opPackageName, cookie,
@@ -421,7 +422,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
- allowBackgroundAuthentication, isKeyguardBypassEnabled);
+ allowBackgroundAuthentication, isKeyguardBypassEnabled, biometricStrength);
scheduleForSensor(sensorId, client);
});
}
@@ -490,7 +491,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext, hardwareAuthToken,
- mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
+ mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
+ Utils.getCurrentStrength(sensorId));
scheduleForSensor(sensorId, client);
});
@@ -623,6 +625,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
}
pw.println(dump);
pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
+ pw.println("---AuthSessionCoordinator logs begin---");
+ pw.println(mBiometricContext.getAuthSessionCoordinator());
+ pw.println("---AuthSessionCoordinator logs end ---");
mSensors.get(sensorId).getScheduler().dump(pw);
mUsageStats.print(pw);
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
index bf7a62aadc28..32bed48aec95 100644
--- 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
@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.face.aidl;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.face.IFace;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.RemoteException;
@@ -48,17 +49,20 @@ public class FaceResetLockoutClient extends HalClientMonitor<AidlSession> implem
private final HardwareAuthToken mHardwareAuthToken;
private final LockoutCache mLockoutCache;
private final LockoutResetDispatcher mLockoutResetDispatcher;
+ private final int mBiometricStrength;
FaceResetLockoutClient(@NonNull Context context,
@NonNull Supplier<AidlSession> lazyDaemon, int userId, String owner, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @Authenticators.Types int biometricStrength) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, logger, biometricContext);
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;
+ mBiometricStrength = biometricStrength;
}
@Override
@@ -85,6 +89,8 @@ public class FaceResetLockoutClient extends HalClientMonitor<AidlSession> implem
void onLockoutCleared() {
resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
mLockoutResetDispatcher);
+ getBiometricContext().getAuthSessionCoordinator()
+ .resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId());
mCallback.onClientFinished(this, true /* success */);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index e0955b7dd450..ba583eb42dbc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired;
+import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.PointerContext;
@@ -45,6 +46,7 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -81,7 +83,9 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
private final Handler mHandler;
private final int mSkipWaitForPowerAcquireMessage;
private final int mSkipWaitForPowerVendorAcquireMessage;
+ private final int mBiometricStrength;
private final long mFingerUpIgnoresPower = 500;
+ private final AuthSessionCoordinator mAuthSessionCoordinator;
@Nullable
private ICancellationSignal mCancellationSignal;
private boolean mIsPointerDown;
@@ -112,7 +116,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
@Nullable ISidefpsController sidefpsController,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
- @NonNull Handler handler) {
+ @NonNull Handler handler,
+ @Authenticators.Types int biometricStrength) {
super(
context,
lazyDaemon,
@@ -154,6 +159,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mSkipWaitForPowerVendorAcquireMessage =
context.getResources().getInteger(
R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage);
+ mBiometricStrength = biometricStrength;
+ mAuthSessionCoordinator = biometricContext.getAuthSessionCoordinator();
if (mSensorProps.isAnySidefpsType()) {
if (Build.isDebuggable()) {
@@ -180,6 +187,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
} else {
mState = STATE_STARTED;
}
+ mAuthSessionCoordinator.authStartedFor(getTargetUserId(), getSensorId(),
+ getRequestId());
}
@NonNull
@@ -193,6 +202,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
protected void handleLifecycleAfterAuth(boolean authenticated) {
if (authenticated) {
mCallback.onClientFinished(this, true /* success */);
+ mAuthSessionCoordinator.authenticatedFor(
+ getTargetUserId(), mBiometricStrength, getSensorId(), getRequestId());
}
}
@@ -294,6 +305,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
}
mSensorOverlays.hide(getSensorId());
+ mAuthSessionCoordinator.authEndedFor(getTargetUserId(), mBiometricStrength, getSensorId(),
+ getRequestId());
}
@Override
@@ -447,6 +460,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mSensorOverlays.hide(getSensorId());
mCallback.onClientFinished(this, false /* success */);
+ mAuthSessionCoordinator.lockOutTimed(getTargetUserId(), mBiometricStrength, getSensorId(),
+ durationMillis, getRequestId());
}
@Override
@@ -470,6 +485,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mSensorOverlays.hide(getSensorId());
mCallback.onClientFinished(this, false /* success */);
+ mAuthSessionCoordinator.lockedOutFor(getTargetUserId(), mBiometricStrength, getSensorId(),
+ getRequestId());
}
@Override
@@ -482,6 +499,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
mHandler.removeMessages(MESSAGE_AUTH_SUCCESS);
// Do not call onError() as that will send an additional callback to coex.
onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true);
+ mAuthSessionCoordinator.authEndedFor(getTargetUserId(),
+ mBiometricStrength, getSensorId(), getRequestId());
}
mHandler.removeMessages(MESSAGE_IGNORE_AUTH);
mHandler.postDelayed(() -> {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 3fe6332fcaa0..774aff1dd72c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -328,7 +328,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext, hardwareAuthToken,
- mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
+ mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher,
+ Utils.getCurrentStrength(sensorId));
scheduleForSensor(sensorId, client);
});
}
@@ -447,7 +448,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mBiometricContext, isStrongBiometric,
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
mUdfpsOverlayController, mSidefpsController, allowBackgroundAuthentication,
- mSensors.get(sensorId).getSensorProperties(), mHandler);
+ mSensors.get(sensorId).getSensorProperties(), mHandler,
+ Utils.getCurrentStrength(sensorId));
scheduleForSensor(sensorId, client, mBiometricStateCallback);
});
}
@@ -702,6 +704,9 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
pw.println(dump);
pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
+ pw.println("---AuthSessionCoordinator logs begin---");
+ pw.println(mBiometricContext.getAuthSessionCoordinator());
+ pw.println("---AuthSessionCoordinator logs end ---");
mSensors.get(sensorId).getScheduler().dump(pw);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index c8148df9ea71..22f504cf5664 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -18,6 +18,7 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import android.annotation.NonNull;
import android.content.Context;
+import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.RemoteException;
@@ -48,17 +49,20 @@ class FingerprintResetLockoutClient extends HalClientMonitor<AidlSession> implem
private final HardwareAuthToken mHardwareAuthToken;
private final LockoutCache mLockoutCache;
private final LockoutResetDispatcher mLockoutResetDispatcher;
+ private final int mBiometricStrength;
FingerprintResetLockoutClient(@NonNull Context context,
@NonNull Supplier<AidlSession> lazyDaemon, int userId, String owner, int sensorId,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
@NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @Authenticators.Types int biometricStrength) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, biometricLogger, biometricContext);
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;
+ mBiometricStrength = biometricStrength;
}
@Override
@@ -89,6 +93,8 @@ class FingerprintResetLockoutClient extends HalClientMonitor<AidlSession> implem
void onLockoutCleared() {
resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
mLockoutResetDispatcher);
+ getBiometricContext().getAuthSessionCoordinator()
+ .resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId());
mCallback.onClientFinished(this, true /* success */);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
index dd7aeb72f7d2..58f338c7a5bb 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
@@ -74,7 +74,7 @@ public class BiometricContextProviderTest {
public void setup() throws RemoteException {
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
mProvider = new BiometricContextProvider(mAmbientDisplayConfiguration, mStatusBarService,
- null /* handler */);
+ null /* handler */, null /* authSessionCoordinator */);
ArgumentCaptor<IBiometricContextListener> captor =
ArgumentCaptor.forClass(IBiometricContextListener.class);
verify(mStatusBarService).setBiometicContextListener(captor.capture());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java
index 47b4bf547ff8..c5a855732e0a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java
@@ -16,6 +16,10 @@
package com.android.server.biometrics.sensors;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_DEFAULT;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_LOCKED;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_UNLOCKED;
+
import static com.google.common.truth.Truth.assertThat;
import android.hardware.biometrics.BiometricManager;
@@ -23,6 +27,8 @@ import android.hardware.biometrics.BiometricManager;
import org.junit.Before;
import org.junit.Test;
+import java.util.Map;
+
public class AuthResultCoordinatorTest {
private AuthResultCoordinator mAuthResultCoordinator;
@@ -33,62 +39,107 @@ public class AuthResultCoordinatorTest {
@Test
public void testDefaultMessage() {
- checkResult(mAuthResultCoordinator.getResult(),
- AuthResult.FAILED,
- BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
+ final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
}
@Test
public void testSingleMessageCoordinator() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
- checkResult(mAuthResultCoordinator.getResult(),
- AuthResult.AUTHENTICATED,
- BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
+
+ final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
}
@Test
public void testLockout() {
mAuthResultCoordinator.lockedOutFor(
BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
- checkResult(mAuthResultCoordinator.getResult(),
- AuthResult.LOCKED_OUT,
- BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
+
+ final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_LOCKED);
}
@Test
- public void testHigherStrengthPrecedence() {
+ public void testConvenientLockout() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
+
+ Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ }
+
+ @Test
+ public void testWeakLockout() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_WEAK);
- checkResult(mAuthResultCoordinator.getResult(),
- AuthResult.AUTHENTICATED,
- BiometricManager.Authenticators.BIOMETRIC_WEAK);
+ Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ }
+
+ @Test
+ public void testStrongLockout() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_STRONG);
- checkResult(mAuthResultCoordinator.getResult(),
- AuthResult.AUTHENTICATED,
- BiometricManager.Authenticators.BIOMETRIC_STRONG);
+
+ final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
}
@Test
- public void testAuthPrecedence() {
+ public void testAuthAndLockout() {
mAuthResultCoordinator.authenticatedFor(
BiometricManager.Authenticators.BIOMETRIC_WEAK);
mAuthResultCoordinator.lockedOutFor(
BiometricManager.Authenticators.BIOMETRIC_WEAK);
- checkResult(mAuthResultCoordinator.getResult(),
- AuthResult.AUTHENTICATED,
- BiometricManager.Authenticators.BIOMETRIC_WEAK);
- }
+ final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED | AUTHENTICATOR_LOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_UNLOCKED | AUTHENTICATOR_LOCKED);
- void checkResult(AuthResult res, int status,
- @BiometricManager.Authenticators.Types int strength) {
- assertThat(res.getStatus()).isEqualTo(status);
- assertThat(res.getBiometricStrength()).isEqualTo(strength);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java
index 9bb0f58db520..6e4487548d64 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java
@@ -22,12 +22,18 @@ import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMET
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.time.Clock;
@Presubmit
@SmallTest
@@ -36,20 +42,51 @@ public class AuthSessionCoordinatorTest {
private static final int SECONDARY_USER = 10;
private AuthSessionCoordinator mCoordinator;
+ @Mock
+ private Clock mClock;
@Before
public void setUp() throws Exception {
- mCoordinator = new AuthSessionCoordinator();
+ MockitoAnnotations.initMocks(this);
+ when(mClock.millis()).thenReturn(0L);
+ mCoordinator = new AuthSessionCoordinator(mClock);
}
@Test
public void testUserUnlocked() {
+ mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_STRONG, 1 /* sensorId */,
+ 0 /* requestId */);
+
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
- mCoordinator.authStartedFor(PRIMARY_USER, 1);
- mCoordinator.authenticatedFor(PRIMARY_USER, BIOMETRIC_WEAK, 1);
+ mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.authenticatedFor(PRIMARY_USER, BIOMETRIC_WEAK, 1 /* sensorId */,
+ 0 /* requestId */);
+
+ assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
+ assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
+ }
+
+ @Test
+ public void testUserLocked() {
+ mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.authStartedFor(PRIMARY_USER, 2 /* sensorId */, 0 /* requestId */);
+ mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_STRONG, 1 /* sensorId */,
+ 0 /* requestId */);
+ mCoordinator.authenticatedFor(PRIMARY_USER, BIOMETRIC_WEAK, 2 /* sensorId */,
+ 0 /* requestId */);
+
+ assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
+ assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
+ assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
+
+ mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.authenticatedFor(PRIMARY_USER, BIOMETRIC_WEAK, 1 /* sensorId */,
+ 0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
@@ -58,15 +95,16 @@ public class AuthSessionCoordinatorTest {
@Test
public void testUserCanAuthDuringLockoutOfSameSession() {
- mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_STRONG);
+ mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_STRONG, 0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
- mCoordinator.authStartedFor(PRIMARY_USER, 1);
- mCoordinator.authStartedFor(PRIMARY_USER, 2);
- mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_WEAK, 2);
+ mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.authStartedFor(PRIMARY_USER, 2 /* sensorId */, 0 /* requestId */);
+ mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_WEAK, 2 /* sensorId */,
+ 0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
@@ -75,7 +113,15 @@ public class AuthSessionCoordinatorTest {
@Test
public void testMultiUserAuth() {
- mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_STRONG);
+ mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_STRONG, 1 /* sensorId */,
+ 0 /* requestId */);
+
+ mCoordinator.authStartedFor(SECONDARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.lockedOutFor(SECONDARY_USER, BIOMETRIC_STRONG, 1 /* sensorId */,
+ 0 /* requestId */);
+
+ mCoordinator.resetLockoutFor(PRIMARY_USER, BIOMETRIC_STRONG, 0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
@@ -85,9 +131,10 @@ public class AuthSessionCoordinatorTest {
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_WEAK)).isFalse();
assertThat(mCoordinator.getCanAuthFor(SECONDARY_USER, BIOMETRIC_STRONG)).isFalse();
- mCoordinator.authStartedFor(PRIMARY_USER, 1);
- mCoordinator.authStartedFor(PRIMARY_USER, 2);
- mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_WEAK, 2);
+ mCoordinator.authStartedFor(PRIMARY_USER, 1 /* sensorId */, 0 /* requestId */);
+ mCoordinator.authStartedFor(PRIMARY_USER, 2 /* sensorId */, 0 /* requestId */);
+ mCoordinator.lockedOutFor(PRIMARY_USER, BIOMETRIC_WEAK, 2 /* sensorId */,
+ 0 /* requestId */);
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
assertThat(mCoordinator.getCanAuthFor(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java
index 8baa1ce3f6c6..0b10a7b35127 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java
@@ -22,6 +22,8 @@ import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMET
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
import android.platform.test.annotations.Presubmit;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -31,6 +33,10 @@ import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.time.Clock;
@SmallTest
@Presubmit
@@ -38,111 +44,155 @@ import org.junit.runner.RunWith;
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class MultiBiometricLockoutStateTest {
private static final int PRIMARY_USER = 0;
- private MultiBiometricLockoutState mCoordinator;
-
- private void unlockAllBiometrics() {
- unlockAllBiometrics(mCoordinator, PRIMARY_USER);
+ private MultiBiometricLockoutState mLockoutState;
+ @Mock
+ private Clock mClock;
+
+ private static void unlockAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) {
+ lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, true /* canAuthenticate */);
+ assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_STRONG)).isTrue();
+ assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_WEAK)).isTrue();
+ assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_CONVENIENCE)).isTrue();
}
- private void lockoutAllBiometrics() {
- lockoutAllBiometrics(mCoordinator, PRIMARY_USER);
+ private static void lockoutAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) {
+ lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, false /* canAuthenticate */);
+ assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_STRONG)).isFalse();
+ assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_WEAK)).isFalse();
+ assertThat(lockoutState.canUserAuthenticate(userId, BIOMETRIC_CONVENIENCE)).isFalse();
}
- private static void unlockAllBiometrics(MultiBiometricLockoutState coordinator, int userId) {
- coordinator.onUserUnlocked(userId, BIOMETRIC_STRONG);
- assertThat(coordinator.canUserAuthenticate(userId, BIOMETRIC_STRONG)).isTrue();
- assertThat(coordinator.canUserAuthenticate(userId, BIOMETRIC_WEAK)).isTrue();
- assertThat(coordinator.canUserAuthenticate(userId, BIOMETRIC_CONVENIENCE)).isTrue();
+ private void unlockAllBiometrics() {
+ unlockAllBiometrics(mLockoutState, PRIMARY_USER);
}
- private static void lockoutAllBiometrics(MultiBiometricLockoutState coordinator, int userId) {
- coordinator.onUserLocked(userId, BIOMETRIC_STRONG);
- assertThat(coordinator.canUserAuthenticate(userId, BIOMETRIC_STRONG)).isFalse();
- assertThat(coordinator.canUserAuthenticate(userId, BIOMETRIC_WEAK)).isFalse();
- assertThat(coordinator.canUserAuthenticate(userId, BIOMETRIC_CONVENIENCE)).isFalse();
+ private void lockoutAllBiometrics() {
+ lockoutAllBiometrics(mLockoutState, PRIMARY_USER);
}
@Before
public void setUp() throws Exception {
- mCoordinator = new MultiBiometricLockoutState();
+ MockitoAnnotations.initMocks(this);
+ when(mClock.millis()).thenReturn(0L);
+ mLockoutState = new MultiBiometricLockoutState(mClock);
}
@Test
public void testInitialStateLockedOut() {
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
}
@Test
public void testConvenienceLockout() {
unlockAllBiometrics();
- mCoordinator.onUserLocked(PRIMARY_USER, BIOMETRIC_CONVENIENCE);
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
+ mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE,
+ false /* canAuthenticate */);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(
+ mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
}
@Test
public void testWeakLockout() {
unlockAllBiometrics();
- mCoordinator.onUserLocked(PRIMARY_USER, BIOMETRIC_WEAK);
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
+ mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, false /* canAuthenticate */);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
+ assertThat(
+ mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
}
@Test
public void testStrongLockout() {
- unlockAllBiometrics();
- mCoordinator.onUserLocked(PRIMARY_USER, BIOMETRIC_STRONG);
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
+ lockoutAllBiometrics();
+ mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG,
+ false /* canAuthenticate */);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
+ assertThat(
+ mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
}
@Test
public void testConvenienceUnlock() {
lockoutAllBiometrics();
- mCoordinator.onUserUnlocked(PRIMARY_USER, BIOMETRIC_CONVENIENCE);
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
+ mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE,
+ true /* canAuthenticate */);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
}
@Test
public void testWeakUnlock() {
lockoutAllBiometrics();
- mCoordinator.onUserUnlocked(PRIMARY_USER, BIOMETRIC_WEAK);
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
+ mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, true /* canAuthenticate */);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
}
@Test
public void testStrongUnlock() {
lockoutAllBiometrics();
- mCoordinator.onUserUnlocked(PRIMARY_USER, BIOMETRIC_STRONG);
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
- assertThat(mCoordinator.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
+ mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG,
+ true /* canAuthenticate */);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
}
@Test
public void multiUser_userOneDoesNotAffectUserTwo() {
final int userOne = 1;
final int userTwo = 2;
- MultiBiometricLockoutState coordinator = new MultiBiometricLockoutState();
- lockoutAllBiometrics(coordinator, userOne);
- lockoutAllBiometrics(coordinator, userTwo);
-
- coordinator.onUserUnlocked(userOne, BIOMETRIC_WEAK);
- assertThat(coordinator.canUserAuthenticate(userOne, BIOMETRIC_STRONG)).isFalse();
- assertThat(coordinator.canUserAuthenticate(userOne, BIOMETRIC_WEAK)).isTrue();
- assertThat(coordinator.canUserAuthenticate(userOne, BIOMETRIC_CONVENIENCE)).isTrue();
-
- assertThat(coordinator.canUserAuthenticate(userTwo, BIOMETRIC_STRONG)).isFalse();
- assertThat(coordinator.canUserAuthenticate(userTwo, BIOMETRIC_WEAK)).isFalse();
- assertThat(coordinator.canUserAuthenticate(userTwo, BIOMETRIC_CONVENIENCE)).isFalse();
+ MultiBiometricLockoutState lockoutState = new MultiBiometricLockoutState(mClock);
+ lockoutAllBiometrics(lockoutState, userOne);
+ lockoutAllBiometrics(lockoutState, userTwo);
+
+ lockoutState.setAuthenticatorTo(userOne, BIOMETRIC_WEAK, true /* canAuthenticate */);
+ assertThat(lockoutState.canUserAuthenticate(userOne, BIOMETRIC_STRONG)).isFalse();
+ assertThat(lockoutState.canUserAuthenticate(userOne, BIOMETRIC_WEAK)).isTrue();
+ assertThat(lockoutState.canUserAuthenticate(userOne, BIOMETRIC_CONVENIENCE)).isTrue();
+
+ assertThat(lockoutState.canUserAuthenticate(userTwo, BIOMETRIC_STRONG)).isFalse();
+ assertThat(lockoutState.canUserAuthenticate(userTwo, BIOMETRIC_WEAK)).isFalse();
+ assertThat(lockoutState.canUserAuthenticate(userTwo, BIOMETRIC_CONVENIENCE)).isFalse();
+ }
+
+ @Test
+ public void testTimedLockout() {
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
+
+ mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG,
+ System.currentTimeMillis() + 1);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
+ assertThat(
+ mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
+ }
+
+ @Test
+ public void testTimedLockoutAfterDuration() {
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
+
+ when(mClock.millis()).thenReturn(0L);
+ mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG, 1);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isFalse();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isFalse();
+ assertThat(
+ mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isFalse();
+
+ when(mClock.millis()).thenReturn(2L);
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_STRONG)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_WEAK)).isTrue();
+ assertThat(mLockoutState.canUserAuthenticate(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isTrue();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index f08d0ef67df3..2dc3583478fb 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -44,6 +44,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -95,6 +96,8 @@ public class FaceAuthenticationClientTest {
private ActivityTaskManager mActivityTaskManager;
@Mock
private ICancellationSignal mCancellationSignal;
+ @Mock
+ private AuthSessionCoordinator mAuthSessionCoordinator;
@Captor
private ArgumentCaptor<OperationContext> mOperationContextCaptor;
@@ -105,6 +108,7 @@ public class FaceAuthenticationClientTest {
public void setup() {
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
i -> i.getArgument(0));
+ when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
}
@Test
@@ -158,7 +162,8 @@ public class FaceAuthenticationClientTest {
false /* requireConfirmation */, 9 /* sensorId */,
mBiometricLogger, mBiometricContext, true /* isStrongBiometric */,
mUsageStats, mLockoutCache, false /* allowBackgroundAuthentication */,
- false /* isKeyguardBypassEnabled */, null /* sensorPrivacyManager */) {
+ false /* isKeyguardBypassEnabled */, null /* sensorPrivacyManager */,
+ 0 /* biometricStrength */) {
@Override
protected ActivityTaskManager getActivityTaskManager() {
return mActivityTaskManager;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index 518946aa761a..2afc4d7f8e40 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -34,6 +34,7 @@ import androidx.test.filters.SmallTest;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -71,6 +72,8 @@ public class SensorTest {
private BiometricLogger mBiometricLogger;
@Mock
private BiometricContext mBiometricContext;
+ @Mock
+ private AuthSessionCoordinator mAuthSessionCoordinator;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
@@ -84,6 +87,8 @@ public class SensorTest {
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
+ when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
+
mScheduler = new UserAwareBiometricScheduler(TAG,
new Handler(mLooper.getLooper()),
BiometricScheduler.SENSOR_TYPE_FACE,
@@ -107,7 +112,7 @@ public class SensorTest {
mScheduler.scheduleClientMonitor(new FaceResetLockoutClient(mContext,
() -> new AidlSession(1, mSession, USER_ID, mHalCallback),
USER_ID, TAG, SENSOR_ID, mBiometricLogger, mBiometricContext,
- HAT, mLockoutCache, mLockoutResetDispatcher));
+ HAT, mLockoutCache, mLockoutResetDispatcher, 0 /* biometricStrength */));
mLooper.dispatchAll();
verifyNotLocked();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index dea4d4fb7c64..d5893df991fd 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -58,6 +58,7 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -127,6 +128,8 @@ public class FingerprintAuthenticationClientTest {
private ICancellationSignal mCancellationSignal;
@Mock
private Probe mLuxProbe;
+ @Mock
+ private AuthSessionCoordinator mAuthSessionCoordinator;
@Captor
private ArgumentCaptor<OperationContext> mOperationContextCaptor;
@Captor
@@ -138,6 +141,7 @@ public class FingerprintAuthenticationClientTest {
@Before
public void setup() {
mContext.addMockSystemService(BiometricManager.class, mBiometricManager);
+ when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
when(mBiometricLogger.getAmbientLightProbe(anyBoolean())).thenAnswer(i ->
new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
@@ -496,7 +500,7 @@ public class FingerprintAuthenticationClientTest {
null /* taskStackListener */, mLockoutCache,
mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication,
mSensorProps,
- new Handler(mLooper.getLooper())) {
+ new Handler(mLooper.getLooper()), 0 /* biometricStrength */) {
@Override
protected ActivityTaskManager getActivityTaskManager() {
return mActivityTaskManager;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
index ff636c840bad..7ae4e17e394d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
@@ -34,6 +34,7 @@ import androidx.test.filters.SmallTest;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -71,6 +72,8 @@ public class SensorTest {
private BiometricLogger mLogger;
@Mock
private BiometricContext mBiometricContext;
+ @Mock
+ private AuthSessionCoordinator mAuthSessionCoordinator;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
@@ -83,6 +86,7 @@ public class SensorTest {
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
+ when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
mScheduler = new UserAwareBiometricScheduler(TAG,
new Handler(mLooper.getLooper()),
@@ -107,7 +111,7 @@ public class SensorTest {
mScheduler.scheduleClientMonitor(new FingerprintResetLockoutClient(mContext,
() -> new AidlSession(1, mSession, USER_ID, mHalCallback),
USER_ID, TAG, SENSOR_ID, mLogger, mBiometricContext, HAT, mLockoutCache,
- mLockoutResetDispatcher));
+ mLockoutResetDispatcher, 0 /* biometricStrength */));
mLooper.dispatchAll();
verifyNotLocked();