From 0b8634d243c5f73981a8fc321988fb7ee602b3cf Mon Sep 17 00:00:00 2001 From: Joe Bolinger Date: Fri, 28 Jan 2022 13:35:30 -0800 Subject: [PATCH] Send AoD context changed notification to HAL. Bug: 204585936 Bug: 204584403 Test: atest FingerprintAuthenticationClientTest FingerprintDetectClientTest FingerprintEnrollClientTest Change-Id: Idcccba362a151d0454d4070475073d07803e4e2a --- .../biometrics/sensors/HalClientMonitor.java | 15 ++++- .../aidl/FingerprintAuthenticationClient.java | 21 +++++-- .../aidl/FingerprintEnrollClient.java | 59 ++++++++++++------- .../statusbar/StatusBarManagerService.java | 6 ++ .../FingerprintAuthenticationClientTest.java | 19 ++++++ .../aidl/FingerprintDetectClientTest.java | 2 - .../aidl/FingerprintEnrollClientTest.java | 44 ++++++++++++++ 7 files changed, 139 insertions(+), 27 deletions(-) diff --git a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java index cc841931f4603..a6e89115400d0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java @@ -82,10 +82,23 @@ public abstract class HalClientMonitor extends BaseClientMonitor { super.destroy(); // subclasses should do this earlier in most cases, but ensure it happens now - getBiometricContext().unsubscribe(mOperationContext); + unsubscribeBiometricContext(); } protected OperationContext getOperationContext() { return getBiometricContext().updateContext(mOperationContext, isCryptoOperation()); } + + protected ClientMonitorCallback getBiometricContextUnsubscriber() { + return new ClientMonitorCallback() { + @Override + public void onClientFinished(@NonNull BaseClientMonitor monitor, boolean success) { + unsubscribeBiometricContext(); + } + }; + } + + protected void unsubscribeBiometricContext() { + getBiometricContext().unsubscribe(mOperationContext); + } } 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 a8d059d514de7..d26a780085298 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 @@ -24,6 +24,7 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired; import android.hardware.biometrics.common.ICancellationSignal; +import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.fingerprint.PointerContext; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.ISidefpsController; @@ -107,7 +108,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient @NonNull @Override protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) { - return new ClientMonitorCompositeCallback(mALSProbeCallback, callback); + return new ClientMonitorCompositeCallback(mALSProbeCallback, + getBiometricContextUnsubscriber(), callback); } @Override @@ -177,8 +179,17 @@ class FingerprintAuthenticationClient extends AuthenticationClient final AidlSession session = getFreshDaemon(); if (session.hasContextMethods()) { - return session.getSession().authenticateWithContext( - mOperationId, getOperationContext()); + final OperationContext opContext = getOperationContext(); + final ICancellationSignal cancel = session.getSession().authenticateWithContext( + mOperationId, opContext); + getBiometricContext().subscribe(opContext, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }); + return cancel; } else { return session.getSession().authenticate(mOperationId); } @@ -187,6 +198,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient @Override protected void stopHalOperation() { mSensorOverlays.hide(getSensorId()); + unsubscribeBiometricContext(); + if (mCancellationSignal != null) { try { mCancellationSignal.cancel(); @@ -216,7 +229,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient context.y = y; context.minor = minor; context.major = major; - context.isAoD = false; // TODO; get value + context.isAoD = getBiometricContext().isAoD(); session.getSession().onPointerDownWithContext(context); } else { session.getSession().onPointerDown(0 /* pointerId */, x, y, minor, major); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index bce972a38cfd0..e21d901b135dc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -23,6 +23,7 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcquired; import android.hardware.biometrics.common.ICancellationSignal; +import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.fingerprint.PointerContext; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; @@ -37,6 +38,8 @@ import android.util.Slog; 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.log.CallbackWithProbe; +import com.android.server.biometrics.log.Probe; import com.android.server.biometrics.sensors.BiometricNotificationUtils; import com.android.server.biometrics.sensors.BiometricUtils; import com.android.server.biometrics.sensors.ClientMonitorCallback; @@ -56,6 +59,7 @@ class FingerprintEnrollClient extends EnrollClient implements Udfps @NonNull private final FingerprintSensorPropertiesInternal mSensorProps; @NonNull private final SensorOverlays mSensorOverlays; + @NonNull private final CallbackWithProbe mALSProbeCallback; private final @FingerprintManager.EnrollReason int mEnrollReason; @Nullable private ICancellationSignal mCancellationSignal; @@ -81,6 +85,8 @@ class FingerprintEnrollClient extends EnrollClient implements Udfps mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController); mMaxTemplatesPerUser = maxTemplatesPerUser; + mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */); + mEnrollReason = enrollReason; if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) { getLogger().disableMetrics(); @@ -90,8 +96,8 @@ class FingerprintEnrollClient extends EnrollClient implements Udfps @NonNull @Override protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) { - return new ClientMonitorCompositeCallback( - getLogger().createALSCallback(true /* startWithClient */), callback); + return new ClientMonitorCompositeCallback(mALSProbeCallback, + getBiometricContextUnsubscriber(), callback); } @Override @@ -139,22 +145,6 @@ class FingerprintEnrollClient extends EnrollClient implements Udfps >= mMaxTemplatesPerUser; } - @Override - protected void stopHalOperation() { - mSensorOverlays.hide(getSensorId()); - - if (mCancellationSignal != null) { - try { - mCancellationSignal.cancel(); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when requesting cancel", e); - onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - mCallback.onClientFinished(this, false /* success */); - } - } - } - @Override protected void startHalOperation() { mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason), this); @@ -176,16 +166,44 @@ class FingerprintEnrollClient extends EnrollClient implements Udfps HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken); if (session.hasContextMethods()) { - return session.getSession().enrollWithContext(hat, getOperationContext()); + final OperationContext opContext = getOperationContext(); + final ICancellationSignal cancel = session.getSession().enrollWithContext( + hat, opContext); + getBiometricContext().subscribe(opContext, ctx -> { + try { + session.getSession().onContextChanged(ctx); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify context changed", e); + } + }); + return cancel; } else { return session.getSession().enroll(hat); } } + @Override + protected void stopHalOperation() { + mSensorOverlays.hide(getSensorId()); + unsubscribeBiometricContext(); + + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when requesting cancel", e); + onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + } + } + @Override public void onPointerDown(int x, int y, float minor, float major) { try { mIsPointerDown = true; + mALSProbeCallback.getProbe().enable(); final AidlSession session = getFreshDaemon(); if (session.hasContextMethods()) { @@ -195,7 +213,7 @@ class FingerprintEnrollClient extends EnrollClient implements Udfps context.y = y; context.minor = minor; context.major = major; - context.isAoD = false; + context.isAoD = getBiometricContext().isAoD(); session.getSession().onPointerDownWithContext(context); } else { session.getSession().onPointerDown(0 /* pointerId */, x, y, minor, major); @@ -209,6 +227,7 @@ class FingerprintEnrollClient extends EnrollClient implements Udfps public void onPointerUp() { try { mIsPointerDown = false; + mALSProbeCallback.getProbe().disable(); final AidlSession session = getFreshDaemon(); if (session.hasContextMethods()) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 344edbbef9c7f..8a87c96fcaaa4 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -158,6 +158,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private final SparseArray mDisplayUiState = new SparseArray<>(); @GuardedBy("mLock") private IUdfpsHbmListener mUdfpsHbmListener; + @GuardedBy("mLock") + private IBiometricContextListener mBiometricContextListener; @GuardedBy("mCurrentRequestAddTilePackages") private final ArrayMap mCurrentRequestAddTilePackages = new ArrayMap<>(); @@ -897,6 +899,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void setBiometicContextListener(IBiometricContextListener listener) { enforceStatusBarService(); + synchronized (mLock) { + mBiometricContextListener = listener; + } if (mBar != null) { try { mBar.setBiometicContextListener(listener); @@ -1327,6 +1332,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D mHandler.post(() -> { synchronized (mLock) { setUdfpsHbmListener(mUdfpsHbmListener); + setBiometicContextListener(mBiometricContextListener); } }); } 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 59e697245cbf8..de0f038e8ec5a 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 @@ -109,6 +109,8 @@ public class FingerprintAuthenticationClientTest { private ArgumentCaptor mOperationContextCaptor; @Captor private ArgumentCaptor mPointerContextCaptor; + @Captor + private ArgumentCaptor> mContextInjector; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @@ -208,6 +210,23 @@ public class FingerprintAuthenticationClientTest { verify(mLuxProbe, times(2)).enable(); } + @Test + public void notifyHalWhenContextChanges() throws RemoteException { + final FingerprintAuthenticationClient client = createClient(); + client.start(mCallback); + + verify(mHal).authenticateWithContext(eq(OP_ID), mOperationContextCaptor.capture()); + OperationContext opContext = mOperationContextCaptor.getValue(); + + // fake an update to the context + verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture()); + mContextInjector.getValue().accept(opContext); + verify(mHal).onContextChanged(eq(opContext)); + + client.stopHalOperation(); + verify(mBiometricContext).unsubscribe(same(opContext)); + } + @Test public void showHideOverlay_cancel() throws RemoteException { showHideOverlay(c -> c.cancel()); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java index 91b21357e9aaa..93cbef19aca9b 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java @@ -55,7 +55,6 @@ import org.mockito.junit.MockitoRule; public class FingerprintDetectClientTest { private static final int USER_ID = 8; - private static final boolean HAS_AOD = true; @Rule public final TestableContext mContext = new TestableContext( @@ -85,7 +84,6 @@ public class FingerprintDetectClientTest { @Before public void setup() { - when(mBiometricContext.isAoD()).thenReturn(HAS_AOD); when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer( i -> i.getArgument(0)); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java index 018d277c7c445..5a96f5cca52a1 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.same; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -47,6 +48,8 @@ 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.log.CallbackWithProbe; +import com.android.server.biometrics.log.Probe; import com.android.server.biometrics.sensors.BiometricUtils; import com.android.server.biometrics.sensors.ClientMonitorCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; @@ -101,16 +104,22 @@ public class FingerprintEnrollClientTest { private ClientMonitorCallback mCallback; @Mock private Sensor.HalSessionCallback mHalSessionCallback; + @Mock + private Probe mLuxProbe; @Captor private ArgumentCaptor mOperationContextCaptor; @Captor private ArgumentCaptor mPointerContextCaptor; + @Captor + private ArgumentCaptor> mContextInjector; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); @Before public void setup() { + when(mBiometricLogger.createALSCallback(anyBoolean())).thenAnswer(i -> + new CallbackWithProbe<>(mLuxProbe, i.getArgument(0))); when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer( i -> i.getArgument(0)); } @@ -185,6 +194,41 @@ public class FingerprintEnrollClientTest { assertThat(pContext.pointerId).isEqualTo(POINTER_ID); } + @Test + public void luxProbeWhenFingerDown() throws RemoteException { + final FingerprintEnrollClient client = createClient(); + client.start(mCallback); + + client.onPointerDown(TOUCH_X, TOUCH_Y, TOUCH_MAJOR, TOUCH_MINOR); + verify(mLuxProbe).enable(); + + client.onAcquired(2, 0); + verify(mLuxProbe, never()).disable(); + + client.onPointerUp(); + verify(mLuxProbe).disable(); + + client.onPointerDown(TOUCH_X, TOUCH_Y, TOUCH_MAJOR, TOUCH_MINOR); + verify(mLuxProbe, times(2)).enable(); + } + + @Test + public void notifyHalWhenContextChanges() throws RemoteException { + final FingerprintEnrollClient client = createClient(); + client.start(mCallback); + + verify(mHal).enrollWithContext(any(), mOperationContextCaptor.capture()); + OperationContext opContext = mOperationContextCaptor.getValue(); + + // fake an update to the context + verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture()); + mContextInjector.getValue().accept(opContext); + verify(mHal).onContextChanged(eq(opContext)); + + client.stopHalOperation(); + verify(mBiometricContext).unsubscribe(same(opContext)); + } + @Test public void showHideOverlay_cancel() throws RemoteException { showHideOverlay(c -> c.cancel());