diff options
4 files changed, 205 insertions, 51 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d441b31a0996..098603e5ab5d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3534,6 +3534,16 @@ automatically dismissing. This is currently used in SideFpsEventHandler --> <integer name="config_sideFpsToastTimeout">3000</integer> + <!-- This acquired message will cause the sidefpsKgPowerPress window to be skipped. + If this is set to BIOMETRIC_ACQUIRED_VENDOR, then the framework will skip on + config_sidefpsSkipWaitForPowerVendorAcquireMessage --> + <integer name="config_sidefpsSkipWaitForPowerAcquireMessage">6</integer> + + <!-- This vendor acquired message that will cause the sidefpsKgPowerPress window to be skipped. + config_sidefpsSkipWaitForPowerOnFingerUp must be true and + config_sidefpsSkipWaitForPowerAcquireMessage must be BIOMETRIC_ACQUIRED_VENDOR == 6. --> + <integer name="config_sidefpsSkipWaitForPowerVendorAcquireMessage">2</integer> + <!-- This config is used to force VoiceInteractionService to start on certain low ram devices. It declares the package name of VoiceInteractionService that should be started. --> <string translatable="false" name="config_forceVoiceInteractionServicePackage"></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 3ddaddd6ba40..456ec433f908 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2634,6 +2634,8 @@ <java-symbol type="integer" name="config_sidefpsKeyguardPowerPressWindow"/> <java-symbol type="integer" name="config_sidefpsPostAuthDowntime"/> <java-symbol type="integer" name="config_sideFpsToastTimeout"/> + <java-symbol type="integer" name="config_sidefpsSkipWaitForPowerAcquireMessage"/> + <java-symbol type="integer" name="config_sidefpsSkipWaitForPowerVendorAcquireMessage"/> <!-- Clickable toast used during sidefps enrollment --> <java-symbol type="layout" name="side_fps_toast" /> 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 e1626f014d8b..b530c8db3c67 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<AidlSession> 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<Probe> 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<Probe> 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<AidlSession> 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<AidlSession> return false; } - @Override - public void onAuthenticated( + public void handleAuthenticate( BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> 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); + 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<Byte> token) { - 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<AidlSession> // 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<AidlSession> 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 ea1e49d8748a..a149f3ee3f53 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<PointerContext> mPointerContextCaptor; @Captor private ArgumentCaptor<Consumer<OperationContext>> 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() { |