From 25403b7de5c283c78e1e623b9924abe50350a7eb Mon Sep 17 00:00:00 2001 From: Joshua McCloskey Date: Tue, 16 Aug 2022 19:33:31 +0000 Subject: [PATCH] Skip wait for power window Test: atest FingerprintAuthenticationClient Fixes: 242265123 Change-Id: I99509bca62168bf0d2909b964ef5ef9a4dc5429a --- core/res/res/values/config.xml | 10 ++ core/res/res/values/symbols.xml | 2 + .../aidl/FingerprintAuthenticationClient.java | 140 +++++++++++++----- .../FingerprintAuthenticationClientTest.java | 104 +++++++++++-- 4 files changed, 205 insertions(+), 51 deletions(-) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 31ea98ccfb00a..1bbd6080aad6a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3526,6 +3526,16 @@ automatically dismissing. This is currently used in SideFpsEventHandler --> 3000 + + 6 + + + 2 + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d03550c1777c1..f00753845c012 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2631,6 +2631,8 @@ + + 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 e1626f014d8b8..b530c8db3c67b 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 @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; +import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.TaskStackListener; @@ -65,22 +67,28 @@ import java.util.function.Supplier; class FingerprintAuthenticationClient extends AuthenticationClient implements Udfps, LockoutConsumer, PowerPressHandler { private static final String TAG = "FingerprintAuthenticationClient"; - - @NonNull private final LockoutCache mLockoutCache; - @NonNull private final SensorOverlays mSensorOverlays; - @NonNull private final FingerprintSensorPropertiesInternal mSensorProps; - @NonNull private final CallbackWithProbe mALSProbeCallback; - + private static final int MESSAGE_IGNORE_AUTH = 1; + private static final int MESSAGE_AUTH_SUCCESS = 2; + private static final int MESSAGE_FINGER_UP = 3; + @NonNull + private final LockoutCache mLockoutCache; + @NonNull + private final SensorOverlays mSensorOverlays; + @NonNull + private final FingerprintSensorPropertiesInternal mSensorProps; + @NonNull + private final CallbackWithProbe mALSProbeCallback; + private final Handler mHandler; + private final int mSkipWaitForPowerAcquireMessage; + private final int mSkipWaitForPowerVendorAcquireMessage; + private final long mFingerUpIgnoresPower = 500; @Nullable private ICancellationSignal mCancellationSignal; private boolean mIsPointerDown; - private final Handler mHandler; - - private static final int MESSAGE_IGNORE_AUTH = 1; - private static final int MESSAGE_AUTH_SUCCESS = 2; private long mWaitForAuthKeyguard; private long mWaitForAuthBp; private long mIgnoreAuthFor; + private Runnable mAuthSuccessRunnable; FingerprintAuthenticationClient( @NonNull Context context, @@ -140,6 +148,13 @@ class FingerprintAuthenticationClient extends AuthenticationClient mIgnoreAuthFor = context.getResources().getInteger(R.integer.config_sidefpsPostAuthDowntime); + mSkipWaitForPowerAcquireMessage = + context.getResources().getInteger( + R.integer.config_sidefpsSkipWaitForPowerAcquireMessage); + mSkipWaitForPowerVendorAcquireMessage = + context.getResources().getInteger( + R.integer.config_sidefpsSkipWaitForPowerVendorAcquireMessage); + if (mSensorProps.isAnySidefpsType()) { if (Build.isDebuggable()) { mWaitForAuthKeyguard = Settings.Secure.getIntForUser(context.getContentResolver(), @@ -187,38 +202,55 @@ class FingerprintAuthenticationClient extends AuthenticationClient return false; } + public void handleAuthenticate( + BiometricAuthenticator.Identifier identifier, + boolean authenticated, + ArrayList token) { + if (authenticated && mSensorProps.isAnySidefpsType()) { + Slog.i(TAG, "(sideFPS): No power press detected, sending auth"); + } + super.onAuthenticated(identifier, authenticated, token); + if (authenticated) { + mState = STATE_STOPPED; + mSensorOverlays.hide(getSensorId()); + } else { + mState = STATE_STARTED_PAUSED_ATTEMPTED; + } + } + @Override public void onAuthenticated( BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList token) { - long delay = 0; - if (authenticated && mSensorProps.isAnySidefpsType()) { - if (mHandler.hasMessages(MESSAGE_IGNORE_AUTH)) { - Slog.i(TAG, "(sideFPS) Ignoring auth due to recent power press"); - onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true); - return; - } - delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp; - Slog.i(TAG, "(sideFPS) Auth succeeded, sideFps waiting for power until: " + delay); - } - - mHandler.postDelayed( + mHandler.post( () -> { + long delay = 0; if (authenticated && mSensorProps.isAnySidefpsType()) { - Slog.i(TAG, "(sideFPS): No power press detected, sending auth"); + if (mHandler.hasMessages(MESSAGE_IGNORE_AUTH)) { + Slog.i(TAG, "(sideFPS) Ignoring auth due to recent power press"); + onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, + true); + return; + } + delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp; + Slog.i(TAG, "(sideFPS) Auth succeeded, sideFps waiting for power for: " + + delay + "ms"); } - super.onAuthenticated(identifier, authenticated, token); - if (authenticated) { - mState = STATE_STOPPED; - mSensorOverlays.hide(getSensorId()); - } else { - mState = STATE_STARTED_PAUSED_ATTEMPTED; + + if (mHandler.hasMessages(MESSAGE_FINGER_UP)) { + Slog.i(TAG, "Finger up detected, sending auth"); + delay = 0; } - }, - MESSAGE_AUTH_SUCCESS, - delay); + + mAuthSuccessRunnable = + () -> handleAuthenticate(identifier, authenticated, token); + mHandler.postDelayed( + mAuthSuccessRunnable, + MESSAGE_AUTH_SUCCESS, + delay); + }); } @Override @@ -227,6 +259,30 @@ class FingerprintAuthenticationClient extends AuthenticationClient // for most ACQUIRED messages. See BiometricFingerprintConstants#FingerprintAcquired mSensorOverlays.ifUdfps(controller -> controller.onAcquired(getSensorId(), acquiredInfo)); super.onAcquired(acquiredInfo, vendorCode); + if (mSensorProps.isAnySidefpsType()) { + final boolean shouldLookForVendor = + mSkipWaitForPowerAcquireMessage == FINGERPRINT_ACQUIRED_VENDOR; + final boolean acquireMessageMatch = acquiredInfo == mSkipWaitForPowerAcquireMessage; + final boolean vendorMessageMatch = vendorCode == mSkipWaitForPowerVendorAcquireMessage; + final boolean ignorePowerPress = + (acquireMessageMatch && !shouldLookForVendor) || (shouldLookForVendor + && acquireMessageMatch && vendorMessageMatch); + + if (ignorePowerPress) { + Slog.d(TAG, "(sideFPS) onFingerUp"); + mHandler.post(() -> { + if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) { + Slog.d(TAG, "(sideFPS) skipping wait for power"); + mHandler.removeMessages(MESSAGE_AUTH_SUCCESS); + mHandler.post(mAuthSuccessRunnable); + } else { + mHandler.postDelayed(() -> { + }, MESSAGE_FINGER_UP, mFingerUpIgnoresPower); + } + }); + } + } + } @Override @@ -418,14 +474,18 @@ class FingerprintAuthenticationClient extends AuthenticationClient public void onPowerPressed() { if (mSensorProps.isAnySidefpsType()) { Slog.i(TAG, "(sideFPS): onPowerPressed"); - if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) { - Slog.i(TAG, "(sideFPS): Ignoring auth in queue"); - 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); - } - mHandler.removeMessages(MESSAGE_IGNORE_AUTH); - mHandler.postDelayed(() -> {}, MESSAGE_IGNORE_AUTH, mIgnoreAuthFor); + mHandler.post(() -> { + if (mHandler.hasMessages(MESSAGE_AUTH_SUCCESS)) { + Slog.i(TAG, "(sideFPS): Ignoring auth in queue"); + 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); + } + mHandler.removeMessages(MESSAGE_IGNORE_AUTH); + mHandler.postDelayed(() -> { + }, MESSAGE_IGNORE_AUTH, mIgnoreAuthFor); + + }); } } } 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 ea1e49d8748a9..a149f3ee3f536 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 @@ -53,6 +53,7 @@ import android.testing.TestableContext; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.internal.R; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.log.CallbackWithProbe; @@ -88,11 +89,13 @@ public class FingerprintAuthenticationClientTest { private static final int TOUCH_Y = 20; private static final float TOUCH_MAJOR = 4.4f; private static final float TOUCH_MINOR = 5.5f; + private static final int FINGER_UP = 111; @Rule public final TestableContext mContext = new TestableContext( InstrumentationRegistry.getInstrumentation().getTargetContext(), null); - + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); @Mock private ISession mHal; @Mock @@ -129,11 +132,7 @@ public class FingerprintAuthenticationClientTest { private ArgumentCaptor mPointerContextCaptor; @Captor private ArgumentCaptor> mContextInjector; - - private TestLooper mLooper = new TestLooper(); - - @Rule - public final MockitoRule mockito = MockitoJUnit.rule(); + private final TestLooper mLooper = new TestLooper(); @Before public void setup() { @@ -358,16 +357,97 @@ public class FingerprintAuthenticationClientTest { final FingerprintAuthenticationClient client = createClient(1); client.start(mCallback); client.onPowerPressed(); + mLooper.dispatchAll(); mLooper.moveTimeForward(1000); mLooper.dispatchAll(); client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */), true /* authenticated */, new ArrayList<>()); + mLooper.dispatchAll(); mLooper.moveTimeForward(1000); mLooper.dispatchAll(); verify(mCallback).onClientFinished(any(), eq(true)); } + @Test + public void sideFingerprintDoesntSendAuthImmediately() throws Exception { + when(mSensorProps.isAnySidefpsType()).thenReturn(true); + + final FingerprintAuthenticationClient client = createClient(1); + client.start(mCallback); + mLooper.dispatchAll(); + client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */), + true /* authenticated */, new ArrayList<>()); + mLooper.dispatchAll(); + + verify(mCallback, never()).onClientFinished(any(), anyBoolean()); + } + + @Test + public void sideFingerprintSkipsWindowIfFingerUp() throws Exception { + when(mSensorProps.isAnySidefpsType()).thenReturn(true); + + mContext.getOrCreateTestableResources().addOverride( + R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP); + + final FingerprintAuthenticationClient client = createClient(1); + client.start(mCallback); + mLooper.dispatchAll(); + client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */), + true /* authenticated */, new ArrayList<>()); + client.onAcquired(FINGER_UP, 0); + mLooper.dispatchAll(); + + verify(mCallback).onClientFinished(any(), eq(true)); + } + + @Test + public void sideFingerprintSendsAuthIfFingerUp() throws Exception { + when(mSensorProps.isAnySidefpsType()).thenReturn(true); + + mContext.getOrCreateTestableResources().addOverride( + R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP); + + final FingerprintAuthenticationClient client = createClient(1); + client.start(mCallback); + mLooper.dispatchAll(); + client.onAcquired(FINGER_UP, 0); + client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */), + true /* authenticated */, new ArrayList<>()); + mLooper.dispatchAll(); + + verify(mCallback).onClientFinished(any(), eq(true)); + } + + @Test + public void sideFingerprintShortCircuitExpires() throws Exception { + when(mSensorProps.isAnySidefpsType()).thenReturn(true); + + final int timeBeforeAuthSent = 500; + + mContext.getOrCreateTestableResources().addOverride( + R.integer.config_sidefpsKeyguardPowerPressWindow, timeBeforeAuthSent); + mContext.getOrCreateTestableResources().addOverride( + R.integer.config_sidefpsSkipWaitForPowerAcquireMessage, FINGER_UP); + + final FingerprintAuthenticationClient client = createClient(1); + client.start(mCallback); + mLooper.dispatchAll(); + client.onAcquired(FINGER_UP, 0); + mLooper.dispatchAll(); + + mLooper.moveTimeForward(500); + mLooper.dispatchAll(); + client.onAuthenticated(new Fingerprint("friendly", 4 /* fingerId */, 5 /* deviceId */), + true /* authenticated */, new ArrayList<>()); + mLooper.dispatchAll(); + verify(mCallback, never()).onClientFinished(any(), anyBoolean()); + + mLooper.moveTimeForward(500); + mLooper.dispatchAll(); + verify(mCallback).onClientFinished(any(), eq(true)); + } + private FingerprintAuthenticationClient createClient() throws RemoteException { return createClient(100 /* version */, true /* allowBackgroundAuthentication */); } @@ -388,11 +468,13 @@ public class FingerprintAuthenticationClientTest { final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback); return new FingerprintAuthenticationClient(mContext, () -> aidl, mToken, REQUEST_ID, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID, - false /* restricted */, "test-owner", 4 /* cookie */, false /* requireConfirmation */, - 9 /* sensorId */, mBiometricLogger, mBiometricContext, - true /* isStrongBiometric */, - null /* taskStackListener */, mLockoutCache, - mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication, mSensorProps, + false /* restricted */, "test-owner", 4 /* cookie */, + false /* requireConfirmation */, + 9 /* sensorId */, mBiometricLogger, mBiometricContext, + true /* isStrongBiometric */, + null /* taskStackListener */, mLockoutCache, + mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication, + mSensorProps, new Handler(mLooper.getLooper())) { @Override protected ActivityTaskManager getActivityTaskManager() {