diff options
12 files changed, 213 insertions, 130 deletions
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 a48a9d1c3eaa..cd2a26fbd3e4 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java @@ -37,13 +37,17 @@ class AuthResultCoordinator { */ static final int AUTHENTICATOR_DEFAULT = 0; /** - * Indicated this authenticator has received a lockout. + * Indicated this authenticator has received a permanent lockout. */ - static final int AUTHENTICATOR_LOCKED = 1 << 0; + static final int AUTHENTICATOR_PERMANENT_LOCKED = 1 << 0; + /** + * Indicates this authenticator has received a timed unlock. + */ + static final int AUTHENTICATOR_TIMED_LOCKED = 1 << 1; /** * Indicates this authenticator has received a successful unlock. */ - static final int AUTHENTICATOR_UNLOCKED = 1 << 1; + static final int AUTHENTICATOR_UNLOCKED = 1 << 2; private static final String TAG = "AuthResultCoordinator"; private final Map<Integer, Integer> mAuthenticatorState; @@ -85,7 +89,14 @@ class AuthResultCoordinator { * Adds a lock out of a given strength to the current operation list. */ void lockedOutFor(@Authenticators.Types int strength) { - updateState(strength, (old) -> AUTHENTICATOR_LOCKED | old); + updateState(strength, (old) -> AUTHENTICATOR_PERMANENT_LOCKED | old); + } + + /** + * Adds a timed lock out of a given strength to the current operation list. + */ + void lockOutTimed(@Authenticators.Types int strength) { + updateState(strength, (old) -> AUTHENTICATOR_TIMED_LOCKED | old); } /** 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 1aee5d48b9ee..2653ce76459d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java @@ -16,21 +16,19 @@ 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_PERMANENT_LOCKED; +import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_TIMED_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; @@ -45,9 +43,7 @@ public class AuthSessionCoordinator implements AuthSessionListener { 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; @@ -63,8 +59,6 @@ public class AuthSessionCoordinator implements AuthSessionListener { mAuthResultCoordinator = new AuthResultCoordinator(); mMultiBiometricLockoutState = new MultiBiometricLockoutState(clock); mRingBuffer = new RingBuffer(100); - mTimedLockouts = new ArrayList<>(); - mClock = clock; } /** @@ -74,8 +68,6 @@ public class AuthSessionCoordinator implements AuthSessionListener { mAuthOperations.clear(); mUserId = userId; mIsAuthenticating = true; - mAuthOperations.clear(); - mTimedLockouts.clear(); mAuthResultCoordinator = new AuthResultCoordinator(); mRingBuffer.addApiCall("internal : onAuthSessionStarted(" + userId + ")"); } @@ -85,39 +77,30 @@ public class AuthSessionCoordinator implements AuthSessionListener { * * This can happen two ways. * 1. Manually calling this API - * 2. If authStartedFor() was called, and all authentication attempts finish. + * 2. If authStartedFor() was called, and any authentication attempts finish. */ void endAuthSession() { - if (mIsAuthenticating) { - 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 */); - } - + // 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.clearPermanentLockOut(mUserId, authenticator); + mMultiBiometricLockoutState.clearTimedLockout(mUserId, authenticator); + } else if ((value & AUTHENTICATOR_PERMANENT_LOCKED) == AUTHENTICATOR_PERMANENT_LOCKED) { + mMultiBiometricLockoutState.setPermanentLockOut(mUserId, authenticator); + } else if ((value & AUTHENTICATOR_TIMED_LOCKED) == AUTHENTICATOR_TIMED_LOCKED) { + mMultiBiometricLockoutState.setTimedLockout(mUserId, authenticator); } - - mRingBuffer.addApiCall("internal : onAuthSessionEnded(" + mUserId + ")"); - clearSession(); } + + mRingBuffer.addApiCall("internal : onAuthSessionEnded(" + mUserId + ")"); + clearSession(); } private void clearSession() { mIsAuthenticating = false; - mTimedLockouts.clear(); mAuthOperations.clear(); } @@ -171,7 +154,7 @@ public class AuthSessionCoordinator implements AuthSessionListener { + ", sensorId=" + sensorId + "time=" + time + ", requestId=" + requestId + ")"; mRingBuffer.addApiCall(lockedOutStr); - mTimedLockouts.add(new Pair<>(biometricStrength, time)); + mAuthResultCoordinator.lockOutTimed(biometricStrength); attemptToFinish(userId, sensorId, lockedOutStr); } @@ -202,9 +185,8 @@ public class AuthSessionCoordinator implements AuthSessionListener { // Lockouts cannot be reset by non-strong biometrics return; } - mMultiBiometricLockoutState.setAuthenticatorTo(userId, biometricStrength, - true /*canAuthenticate */); - mMultiBiometricLockoutState.clearLockoutTime(userId, biometricStrength); + mMultiBiometricLockoutState.clearPermanentLockOut(userId, biometricStrength); + mMultiBiometricLockoutState.clearTimedLockout(userId, biometricStrength); } private void attemptToFinish(int userId, int sensorId, String description) { 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 c24a98940519..45933fe748dc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java +++ b/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java @@ -50,10 +50,11 @@ class MultiBiometricLockoutState { 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)); + new AuthenticatorState(BIOMETRIC_STRONG, false, false)); + lockOutMap.put(BIOMETRIC_WEAK, + new AuthenticatorState(BIOMETRIC_WEAK, false, false)); lockOutMap.put(BIOMETRIC_CONVENIENCE, - new AuthenticatorState(BIOMETRIC_CONVENIENCE, false, 0, mClock)); + new AuthenticatorState(BIOMETRIC_CONVENIENCE, false, false)); return lockOutMap; } @@ -64,54 +65,71 @@ class MultiBiometricLockoutState { return mCanUserAuthenticate.get(userId); } - void setAuthenticatorTo(int userId, @Authenticators.Types int strength, boolean canAuth) { + void setPermanentLockOut(int userId, @Authenticators.Types int strength) { final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId); switch (strength) { case Authenticators.BIOMETRIC_STRONG: - authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = !canAuth; + authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = true; // fall through case Authenticators.BIOMETRIC_WEAK: - authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = !canAuth; + authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = true; // fall through case Authenticators.BIOMETRIC_CONVENIENCE: - authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = !canAuth; + authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = true; return; default: Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength); } } - void increaseLockoutTime(int userId, @Authenticators.Types int strength, long duration) { + void clearPermanentLockOut(int userId, @Authenticators.Types int strength) { final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId); switch (strength) { case Authenticators.BIOMETRIC_STRONG: - authMap.get(BIOMETRIC_STRONG).increaseLockoutTo(duration); + authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = false; // fall through case Authenticators.BIOMETRIC_WEAK: - authMap.get(BIOMETRIC_WEAK).increaseLockoutTo(duration); + authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = false; // fall through case Authenticators.BIOMETRIC_CONVENIENCE: - authMap.get(BIOMETRIC_CONVENIENCE).increaseLockoutTo(duration); + authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = false; return; default: Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength); } } - void clearLockoutTime(int userId, @Authenticators.Types int strength) { + void setTimedLockout(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); + authMap.get(BIOMETRIC_STRONG).mTimedLockout = true; // fall through case Authenticators.BIOMETRIC_WEAK: - authMap.get(BIOMETRIC_WEAK).setTimedLockout(0); + authMap.get(BIOMETRIC_WEAK).mTimedLockout = true; // fall through case Authenticators.BIOMETRIC_CONVENIENCE: - authMap.get(BIOMETRIC_CONVENIENCE).setTimedLockout(0); + authMap.get(BIOMETRIC_CONVENIENCE).mTimedLockout = true; return; default: - Slog.e(TAG, "clearLockoutTime called for invalid strength : " + strength); + Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength); + } + } + + void clearTimedLockout(int userId, @Authenticators.Types int strength) { + final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId); + switch (strength) { + case Authenticators.BIOMETRIC_STRONG: + authMap.get(BIOMETRIC_STRONG).mTimedLockout = false; + // fall through + case Authenticators.BIOMETRIC_WEAK: + authMap.get(BIOMETRIC_WEAK).mTimedLockout = false; + // fall through + case Authenticators.BIOMETRIC_CONVENIENCE: + authMap.get(BIOMETRIC_CONVENIENCE).mTimedLockout = false; + return; + default: + Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength); } } @@ -132,7 +150,7 @@ class MultiBiometricLockoutState { final AuthenticatorState state = authMap.get(strength); if (state.mPermanentlyLockedOut) { return LockoutTracker.LOCKOUT_PERMANENT; - } else if (state.isTimedLockout()) { + } else if (state.mTimedLockout) { return LockoutTracker.LOCKOUT_TIMED; } else { return LockoutTracker.LOCKOUT_NONE; @@ -158,43 +176,21 @@ class MultiBiometricLockoutState { private static class AuthenticatorState { private Integer mAuthenticatorType; private boolean mPermanentlyLockedOut; - private long mTimedLockout; - private Clock mClock; + private boolean mTimedLockout; AuthenticatorState(Integer authenticatorId, boolean permanentlyLockedOut, - long timedLockout, Clock clock) { + boolean timedLockout) { mAuthenticatorType = authenticatorId; mPermanentlyLockedOut = permanentlyLockedOut; mTimedLockout = timedLockout; - mClock = clock; - } - - boolean canAuthenticate() { - return !mPermanentlyLockedOut && !isTimedLockout(); - } - - boolean isTimedLockout() { - return mClock.millis() - mTimedLockout < 0; - } - - void setTimedLockout(long duration) { - mTimedLockout = duration; - } - - /** - * Either increases the lockout to duration, or leaves it as it, whichever is longer. - */ - void increaseLockoutTo(long duration) { - mTimedLockout = Math.max(mTimedLockout, duration); } String toString(long currentTime) { - final String duration = - mTimedLockout - currentTime > 0 ? (mTimedLockout - currentTime) + "ms" : "none"; + final String timedLockout = mTimedLockout ? "true" : "false"; final String permanentLockout = mPermanentlyLockedOut ? "true" : "false"; - return String.format("(%s, permanentLockout=%s, timedLockoutRemaining=%s)", + return String.format("(%s, permanentLockout=%s, timedLockout=%s)", BiometricManager.authenticatorToStr(mAuthenticatorType), permanentLockout, - duration); + timedLockout); } } } 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 759c52a45807..1a12fcdf5010 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 @@ -28,6 +28,7 @@ import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.HardwareAuthTokenUtils; 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.ErrorConsumer; import com.android.server.biometrics.sensors.HalClientMonitor; @@ -88,10 +89,9 @@ public class FaceResetLockoutClient extends HalClientMonitor<AidlSession> implem void onLockoutCleared() { resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache, - mLockoutResetDispatcher); + mLockoutResetDispatcher, getBiometricContext().getAuthSessionCoordinator(), + mBiometricStrength, getRequestId()); mCallback.onClientFinished(this, true /* success */); - getBiometricContext().getAuthSessionCoordinator() - .resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId()); } public boolean interruptsPrecedingClients() { @@ -108,7 +108,10 @@ public class FaceResetLockoutClient extends HalClientMonitor<AidlSession> implem */ static void resetLocalLockoutStateToNone(int sensorId, int userId, @NonNull LockoutCache lockoutTracker, - @NonNull LockoutResetDispatcher lockoutResetDispatcher) { + @NonNull LockoutResetDispatcher lockoutResetDispatcher, + @NonNull AuthSessionCoordinator authSessionCoordinator, + @Authenticators.Types int biometricStrength, long requestId) { + authSessionCoordinator.resetLockoutFor(userId, biometricStrength, requestId); lockoutTracker.setLockoutModeForUser(userId, LockoutTracker.LOCKOUT_NONE); lockoutResetDispatcher.notifyLockoutResetCallbacks(sensorId); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java index 0d30ddd56699..468bf5530d34 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java @@ -54,6 +54,7 @@ import com.android.server.biometrics.UserStateProto; 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.AuthenticationConsumer; import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; @@ -127,6 +128,9 @@ public class Sensor { private final LockoutCache mLockoutCache; @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; + + @NonNull + private AuthSessionCoordinator mAuthSessionCoordinator; @NonNull private final Callback mCallback; @@ -134,6 +138,7 @@ public class Sensor { @NonNull UserAwareBiometricScheduler scheduler, int sensorId, int userId, @NonNull LockoutCache lockoutTracker, @NonNull LockoutResetDispatcher lockoutResetDispatcher, + @NonNull AuthSessionCoordinator authSessionCoordinator, @NonNull Callback callback) { mContext = context; mHandler = handler; @@ -143,6 +148,7 @@ public class Sensor { mUserId = userId; mLockoutCache = lockoutTracker; mLockoutResetDispatcher = lockoutResetDispatcher; + mAuthSessionCoordinator = authSessionCoordinator; mCallback = callback; } @@ -346,8 +352,12 @@ public class Sensor { final BaseClientMonitor client = mScheduler.getCurrentClient(); if (!(client instanceof FaceResetLockoutClient)) { Slog.d(mTag, "onLockoutCleared outside of resetLockout by HAL"); + // Given that onLockoutCleared() can happen at any time, and is not necessarily + // coming from a specific client, set this to -1 to indicate it wasn't for a + // specific request. FaceResetLockoutClient.resetLocalLockoutStateToNone(mSensorId, mUserId, - mLockoutCache, mLockoutResetDispatcher); + mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator, + Utils.getCurrentStrength(mSensorId), -1 /* requestId */); } else { Slog.d(mTag, "onLockoutCleared after resetLockout"); final FaceResetLockoutClient resetLockoutClient = @@ -514,7 +524,8 @@ public class Sensor { final HalSessionCallback resultController = new HalSessionCallback(mContext, mHandler, mTag, mScheduler, sensorId, newUserId, mLockoutCache, - lockoutResetDispatcher, () -> { + lockoutResetDispatcher, + biometricContext.getAuthSessionCoordinator(), () -> { Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE"); mCurrentSession = null; }); 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 0b2421b745f5..7a620349075c 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 @@ -28,6 +28,7 @@ import com.android.server.biometrics.BiometricsProto; import com.android.server.biometrics.HardwareAuthTokenUtils; 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.ErrorConsumer; import com.android.server.biometrics.sensors.HalClientMonitor; @@ -92,10 +93,9 @@ class FingerprintResetLockoutClient extends HalClientMonitor<AidlSession> implem void onLockoutCleared() { resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache, - mLockoutResetDispatcher); + mLockoutResetDispatcher, getBiometricContext().getAuthSessionCoordinator(), + mBiometricStrength, getRequestId()); mCallback.onClientFinished(this, true /* success */); - getBiometricContext().getAuthSessionCoordinator() - .resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId()); } /** @@ -108,9 +108,12 @@ class FingerprintResetLockoutClient extends HalClientMonitor<AidlSession> implem */ static void resetLocalLockoutStateToNone(int sensorId, int userId, @NonNull LockoutCache lockoutTracker, - @NonNull LockoutResetDispatcher lockoutResetDispatcher) { + @NonNull LockoutResetDispatcher lockoutResetDispatcher, + @NonNull AuthSessionCoordinator authSessionCoordinator, + @Authenticators.Types int biometricStrength, long requestId) { lockoutTracker.setLockoutModeForUser(userId, LockoutTracker.LOCKOUT_NONE); lockoutResetDispatcher.notifyLockoutResetCallbacks(sensorId); + authSessionCoordinator.resetLockoutFor(userId, biometricStrength, requestId); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java index 1dcf4e9528d2..22ca816ba56c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java @@ -52,6 +52,7 @@ 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.AcquisitionClient; +import com.android.server.biometrics.sensors.AuthSessionCoordinator; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; @@ -131,12 +132,15 @@ public class Sensor { @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull + private AuthSessionCoordinator mAuthSessionCoordinator; + @NonNull private final Callback mCallback; HalSessionCallback(@NonNull Context context, @NonNull Handler handler, @NonNull String tag, @NonNull UserAwareBiometricScheduler scheduler, int sensorId, int userId, @NonNull LockoutCache lockoutTracker, @NonNull LockoutResetDispatcher lockoutResetDispatcher, + @NonNull AuthSessionCoordinator authSessionCoordinator, @NonNull Callback callback) { mContext = context; mHandler = handler; @@ -146,6 +150,7 @@ public class Sensor { mUserId = userId; mLockoutCache = lockoutTracker; mLockoutResetDispatcher = lockoutResetDispatcher; + mAuthSessionCoordinator = authSessionCoordinator; mCallback = callback; } @@ -327,8 +332,12 @@ public class Sensor { final BaseClientMonitor client = mScheduler.getCurrentClient(); if (!(client instanceof FingerprintResetLockoutClient)) { Slog.d(mTag, "onLockoutCleared outside of resetLockout by HAL"); + // Given that onLockoutCleared() can happen at any time, and is not necessarily + // coming from a specific client, set this to -1 to indicate it wasn't for a + // specific request. FingerprintResetLockoutClient.resetLocalLockoutStateToNone(mSensorId, mUserId, - mLockoutCache, mLockoutResetDispatcher); + mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator, + Utils.getCurrentStrength(mSensorId), -1 /* requestId */); } else { Slog.d(mTag, "onLockoutCleared after resetLockout"); final FingerprintResetLockoutClient resetLockoutClient = @@ -470,7 +479,8 @@ public class Sensor { final HalSessionCallback resultController = new HalSessionCallback(mContext, mHandler, mTag, mScheduler, sensorId, newUserId, mLockoutCache, - lockoutResetDispatcher, () -> { + lockoutResetDispatcher, + biometricContext.getAuthSessionCoordinator(), () -> { Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE"); mCurrentSession = null; }); 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 ebf7fd8c2752..2102b0962bbf 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 @@ -17,7 +17,8 @@ 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_PERMANENT_LOCKED; +import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_TIMED_LOCKED; import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_UNLOCKED; import static com.google.common.truth.Truth.assertThat; @@ -76,7 +77,22 @@ public class AuthResultCoordinatorTest { assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo( AUTHENTICATOR_DEFAULT); assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo( - AUTHENTICATOR_LOCKED); + AUTHENTICATOR_PERMANENT_LOCKED); + } + + @Test + public void testConvenientLockoutTimed() { + mAuthResultCoordinator.lockOutTimed( + 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_TIMED_LOCKED); } @Test @@ -97,16 +113,31 @@ public class AuthResultCoordinatorTest { @Test public void testWeakLockout() { mAuthResultCoordinator.lockedOutFor( - BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE); + 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_PERMANENT_LOCKED); + assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo( + AUTHENTICATOR_PERMANENT_LOCKED); + } + + @Test + public void testWeakLockoutTimed() { + mAuthResultCoordinator.lockOutTimed( + 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_TIMED_LOCKED); assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo( - AUTHENTICATOR_LOCKED); + AUTHENTICATOR_TIMED_LOCKED); } @Test @@ -132,13 +163,27 @@ public class AuthResultCoordinatorTest { Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult(); assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo( - AUTHENTICATOR_LOCKED); + AUTHENTICATOR_PERMANENT_LOCKED); assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo( - AUTHENTICATOR_LOCKED); + AUTHENTICATOR_PERMANENT_LOCKED); assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo( - AUTHENTICATOR_LOCKED); + AUTHENTICATOR_PERMANENT_LOCKED); } + @Test + public void testStrongLockoutTimed() { + mAuthResultCoordinator.lockOutTimed( + BiometricManager.Authenticators.BIOMETRIC_STRONG); + + Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult(); + + assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo( + AUTHENTICATOR_TIMED_LOCKED); + assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo( + AUTHENTICATOR_TIMED_LOCKED); + assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo( + AUTHENTICATOR_TIMED_LOCKED); + } @Test public void testStrongUnlock() { @@ -167,10 +212,30 @@ public class AuthResultCoordinatorTest { assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo( AUTHENTICATOR_DEFAULT); assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo( - AUTHENTICATOR_LOCKED); + AUTHENTICATOR_PERMANENT_LOCKED); assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo( - AUTHENTICATOR_LOCKED); + AUTHENTICATOR_PERMANENT_LOCKED); + + } + @Test + public void testLockoutAndAuth() { + mAuthResultCoordinator.lockedOutFor( + BiometricManager.Authenticators.BIOMETRIC_WEAK); + mAuthResultCoordinator.authenticatedFor( + BiometricManager.Authenticators.BIOMETRIC_STRONG); + + final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult(); + + assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG) + & AUTHENTICATOR_UNLOCKED).isEqualTo( + AUTHENTICATOR_UNLOCKED); + assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK) + & AUTHENTICATOR_UNLOCKED).isEqualTo( + AUTHENTICATOR_UNLOCKED); + assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE) + & AUTHENTICATOR_UNLOCKED).isEqualTo( + AUTHENTICATOR_UNLOCKED); } } 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 c3b9cb17ead8..f26c7e63a273 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 @@ -154,7 +154,7 @@ public class AuthSessionCoordinatorTest { LockoutTracker.LOCKOUT_NONE); assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( LockoutTracker.LOCKOUT_NONE); - assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( + assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_NONE); } @@ -194,7 +194,7 @@ public class AuthSessionCoordinatorTest { LockoutTracker.LOCKOUT_NONE); assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( LockoutTracker.LOCKOUT_NONE); - assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( + assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_NONE); assertThat( 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 968844e4c990..c28de55c7299 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 @@ -49,7 +49,7 @@ public class MultiBiometricLockoutStateTest { private Clock mClock; private static void unlockAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) { - lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, true /* canAuthenticate */); + lockoutState.clearPermanentLockOut(userId, BIOMETRIC_STRONG); assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_NONE); assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_WEAK)).isEqualTo( @@ -59,7 +59,7 @@ public class MultiBiometricLockoutStateTest { } private static void lockoutAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) { - lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, false /* canAuthenticate */); + lockoutState.setPermanentLockOut(userId, BIOMETRIC_STRONG); assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_PERMANENT); assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_WEAK)).isEqualTo( @@ -96,8 +96,7 @@ public class MultiBiometricLockoutStateTest { @Test public void testConvenienceLockout() { unlockAllBiometrics(); - mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE, - false /* canAuthenticate */); + mLockoutState.setPermanentLockOut(PRIMARY_USER, BIOMETRIC_CONVENIENCE); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_NONE); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -110,7 +109,7 @@ public class MultiBiometricLockoutStateTest { @Test public void testWeakLockout() { unlockAllBiometrics(); - mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, false /* canAuthenticate */); + mLockoutState.setPermanentLockOut(PRIMARY_USER, BIOMETRIC_WEAK); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_NONE); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -123,8 +122,7 @@ public class MultiBiometricLockoutStateTest { @Test public void testStrongLockout() { lockoutAllBiometrics(); - mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG, - false /* canAuthenticate */); + mLockoutState.setPermanentLockOut(PRIMARY_USER, BIOMETRIC_STRONG); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_PERMANENT); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -137,8 +135,7 @@ public class MultiBiometricLockoutStateTest { @Test public void testConvenienceUnlock() { lockoutAllBiometrics(); - mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE, - true /* canAuthenticate */); + mLockoutState.clearPermanentLockOut(PRIMARY_USER, BIOMETRIC_CONVENIENCE); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_PERMANENT); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -150,7 +147,7 @@ public class MultiBiometricLockoutStateTest { @Test public void testWeakUnlock() { lockoutAllBiometrics(); - mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, true /* canAuthenticate */); + mLockoutState.clearPermanentLockOut(PRIMARY_USER, BIOMETRIC_WEAK); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_PERMANENT); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -162,8 +159,7 @@ public class MultiBiometricLockoutStateTest { @Test public void testStrongUnlock() { lockoutAllBiometrics(); - mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG, - true /* canAuthenticate */); + mLockoutState.clearPermanentLockOut(PRIMARY_USER, BIOMETRIC_STRONG); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_NONE); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -180,7 +176,7 @@ public class MultiBiometricLockoutStateTest { lockoutAllBiometrics(lockoutState, userOne); lockoutAllBiometrics(lockoutState, userTwo); - lockoutState.setAuthenticatorTo(userOne, BIOMETRIC_WEAK, true /* canAuthenticate */); + lockoutState.clearPermanentLockOut(userOne, BIOMETRIC_WEAK); assertThat(lockoutState.getLockoutState(userOne, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_PERMANENT); assertThat(lockoutState.getLockoutState(userOne, BIOMETRIC_WEAK)).isEqualTo( @@ -205,8 +201,7 @@ public class MultiBiometricLockoutStateTest { assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo( LockoutTracker.LOCKOUT_NONE); - mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG, - System.currentTimeMillis() + 1); + mLockoutState.setTimedLockout(PRIMARY_USER, BIOMETRIC_STRONG); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_TIMED); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -225,8 +220,7 @@ public class MultiBiometricLockoutStateTest { assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo( LockoutTracker.LOCKOUT_NONE); - when(mClock.millis()).thenReturn(0L); - mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG, 1); + mLockoutState.setTimedLockout(PRIMARY_USER, BIOMETRIC_STRONG); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_TIMED); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( @@ -235,7 +229,7 @@ public class MultiBiometricLockoutStateTest { mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo( LockoutTracker.LOCKOUT_TIMED); - when(mClock.millis()).thenReturn(2L); + mLockoutState.clearTimedLockout(PRIMARY_USER, BIOMETRIC_STRONG); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo( LockoutTracker.LOCKOUT_NONE); assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo( 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 1f29becf5cc2..9c9d3f894d95 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 @@ -19,6 +19,8 @@ package com.android.server.biometrics.sensors.face.aidl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; @@ -109,7 +111,8 @@ public class SensorTest { mUserSwitchCallback); mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()), TAG, mScheduler, SENSOR_ID, - USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback); + USER_ID, mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator, + mHalSessionCallback); final SensorProps sensor1 = new SensorProps(); sensor1.commonProps = new CommonProps(); @@ -164,5 +167,6 @@ public class SensorTest { private void verifyNotLocked() { assertEquals(LockoutTracker.LOCKOUT_NONE, mLockoutCache.getLockoutModeForUser(USER_ID)); verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID)); + verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong()); } } 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 7ae4e17e394d..0c1346696b58 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 @@ -18,6 +18,8 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; @@ -97,7 +99,8 @@ public class SensorTest { mUserSwitchCallback); mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()), TAG, mScheduler, SENSOR_ID, - USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback); + USER_ID, mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator, + mHalSessionCallback); } @Test @@ -130,5 +133,6 @@ public class SensorTest { private void verifyNotLocked() { assertEquals(LockoutTracker.LOCKOUT_NONE, mLockoutCache.getLockoutModeForUser(USER_ID)); verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID)); + verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong()); } } |