Merge "Revert "Copy startup & callback mechanism from fingerprint to face service.""

This commit is contained in:
Joe Bolinger
2022-08-17 18:29:32 +00:00
committed by Android (Google) Code Review
31 changed files with 602 additions and 1351 deletions

View File

@@ -29,7 +29,6 @@ import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.CryptoObject;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Binder;
@@ -674,45 +673,6 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
return new ArrayList<>();
}
/**
* Forwards BiometricStateListener to FaceService.
*
* @param listener new BiometricStateListener being added
* @hide
*/
public void registerBiometricStateListener(@NonNull BiometricStateListener listener) {
try {
mService.registerBiometricStateListener(listener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Adds a callback that gets called when the service registers all of the face
* authenticators (HALs).
*
* If the face authenticators are already registered when the callback is added, the
* callback is invoked immediately.
*
* The callback is automatically removed after it's invoked.
*
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void addAuthenticatorsRegisteredCallback(
IFaceAuthenticatorsRegisteredCallback callback) {
if (mService != null) {
try {
mService.addAuthenticatorsRegisteredCallback(callback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
Slog.w(TAG, "addAuthenticatorsRegisteredCallback(): Service not connected!");
}
}
/**
* @hide
*/

View File

@@ -1,35 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.face;
import android.hardware.face.FaceSensorPropertiesInternal;
import java.util.List;
/**
* Callback to notify FaceManager that FaceService has registered all of the
* face authenticators (HALs).
* See {@link android.hardware.face.IFaceService#registerAuthenticators}.
*
* @hide
*/
oneway interface IFaceAuthenticatorsRegisteredCallback {
/**
* Notifies FaceManager that all of the face authenticators have been registered.
*
* @param sensors A consolidated list of sensor properties for all of the authenticators.
*/
void onAllAuthenticatorsRegistered(in List<FaceSensorPropertiesInternal> sensors);
}

View File

@@ -17,11 +17,9 @@ package android.hardware.face;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricStateListener;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -165,11 +163,4 @@ interface IFaceService {
// hidlSensors must be non-null and empty. See AuthService.java
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerAuthenticators(in List<FaceSensorPropertiesInternal> hidlSensors);
// Adds a callback which gets called when the service registers all of the face
// authenticators. The callback is automatically removed after it's invoked.
void addAuthenticatorsRegisteredCallback(IFaceAuthenticatorsRegisteredCallback callback);
// Registers BiometricStateListener.
void registerBiometricStateListener(IBiometricStateListener listener);
}

View File

@@ -202,10 +202,8 @@ interface IFingerprintService {
void setSidefpsController(in ISidefpsController controller);
// Registers BiometricStateListener.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerBiometricStateListener(IBiometricStateListener listener);
// Sends a power button pressed event to all listeners.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
oneway void onPowerPressed();
}

View File

@@ -54,7 +54,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -2019,13 +2018,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// in case authenticators aren't registered yet at this point:
mAuthController.addCallback(new AuthController.Callback() {
@Override
public void onAllAuthenticatorsRegistered(
@BiometricAuthenticator.Modality int modality) {
public void onAllAuthenticatorsRegistered() {
mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
}
@Override
public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
public void onEnrollmentsChanged() {
mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
}
});

View File

@@ -16,7 +16,6 @@
package com.android.keyguard;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static com.android.keyguard.LockIconView.ICON_FINGERPRINT;
@@ -30,7 +29,6 @@ import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedStateListDrawable;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Process;
import android.os.VibrationAttributes;
@@ -703,17 +701,13 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
if (modality == TYPE_FINGERPRINT) {
updateUdfpsConfig();
}
public void onAllAuthenticatorsRegistered() {
updateUdfpsConfig();
}
@Override
public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
if (modality == TYPE_FINGERPRINT) {
updateUdfpsConfig();
}
public void onEnrollmentsChanged() {
updateUdfpsConfig();
}
@Override

View File

@@ -46,7 +46,6 @@ import android.hardware.biometrics.PromptInfo;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
@@ -157,6 +156,25 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
}
};
private final IFingerprintAuthenticatorsRegisteredCallback
mFingerprintAuthenticatorsRegisteredCallback =
new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
mHandler.post(() -> handleAllFingerprintAuthenticatorsRegistered(sensors));
}
};
private final BiometricStateListener mBiometricStateListener =
new BiometricStateListener() {
@Override
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
mHandler.post(
() -> handleEnrollmentsChanged(userId, sensorId, hasEnrollments));
}
};
@VisibleForTesting
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -231,8 +249,8 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
List<FingerprintSensorPropertiesInternal> sensors) {
mExecution.assertIsMainThread();
if (DEBUG) {
Log.d(TAG, "handleAllFingerprintAuthenticatorsRegistered | sensors: "
+ Arrays.toString(sensors.toArray()));
Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString(
sensors.toArray()));
}
mAllFingerprintAuthenticatorsRegistered = true;
mFpProps = sensors;
@@ -274,42 +292,15 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
mSidefpsController = mSidefpsControllerFactory.get();
}
mFingerprintManager.registerBiometricStateListener(new BiometricStateListener() {
@Override
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
mHandler.post(() -> handleEnrollmentsChanged(
TYPE_FINGERPRINT, userId, sensorId, hasEnrollments));
}
});
mFingerprintManager.registerBiometricStateListener(mBiometricStateListener);
updateFingerprintLocation();
for (Callback cb : mCallbacks) {
cb.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT);
cb.onAllAuthenticatorsRegistered();
}
}
private void handleAllFaceAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors) {
mExecution.assertIsMainThread();
if (DEBUG) {
Log.d(TAG, "handleAllFaceAuthenticatorsRegistered | sensors: " + Arrays.toString(
sensors.toArray()));
}
mFaceManager.registerBiometricStateListener(new BiometricStateListener() {
@Override
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
mHandler.post(() -> handleEnrollmentsChanged(
TYPE_FACE, userId, sensorId, hasEnrollments));
}
});
for (Callback cb : mCallbacks) {
cb.onAllAuthenticatorsRegistered(TYPE_FACE);
}
}
private void handleEnrollmentsChanged(@Modality int modality, int userId, int sensorId,
boolean hasEnrollments) {
private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
mExecution.assertIsMainThread();
Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId
+ ", hasEnrollments: " + hasEnrollments);
@@ -323,7 +314,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
}
}
for (Callback cb : mCallbacks) {
cb.onEnrollmentsChanged(modality);
cb.onEnrollmentsChanged();
}
}
@@ -709,26 +700,7 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
if (mFingerprintManager != null) {
mFingerprintManager.addAuthenticatorsRegisteredCallback(
new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
mHandler.post(() ->
handleAllFingerprintAuthenticatorsRegistered(sensors));
}
});
}
if (mFaceManager != null) {
mFaceManager.addAuthenticatorsRegisteredCallback(
new IFaceAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FaceSensorPropertiesInternal> sensors) {
mHandler.post(() ->
handleAllFaceAuthenticatorsRegistered(sensors));
}
}
);
mFingerprintAuthenticatorsRegisteredCallback);
}
mStableDisplaySize = mDisplayManager.getStableDisplaySize();
@@ -1144,13 +1116,13 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
* Called when authenticators are registered. If authenticators are already
* registered before this call, this callback will never be triggered.
*/
default void onAllAuthenticatorsRegistered(@Modality int modality) {}
default void onAllAuthenticatorsRegistered() {}
/**
* Called when enrollments have changed. This is called after boot and on changes to
* Called when UDFPS enrollments have changed. This is called after boot and on changes to
* enrollment.
*/
default void onEnrollmentsChanged(@Modality int modality) {}
default void onEnrollmentsChanged() {}
/**
* Called when the biometric prompt starts showing.

View File

@@ -308,7 +308,7 @@ class AuthRippleController @Inject constructor(
private val authControllerCallback =
object : AuthController.Callback {
override fun onAllAuthenticatorsRegistered(modality: Int) {
override fun onAllAuthenticatorsRegistered() {
updateUdfpsDependentParams()
updateSensorLocation()
}

View File

@@ -16,15 +16,12 @@
package com.android.systemui.doze;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
import android.hardware.biometrics.BiometricAuthenticator;
import android.os.Handler;
import android.util.Log;
import android.view.Display;
@@ -235,17 +232,13 @@ public class DozeScreenState implements DozeMachine.Part {
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
if (modality == TYPE_FINGERPRINT) {
updateUdfpsController();
}
public void onAllAuthenticatorsRegistered() {
updateUdfpsController();
}
@Override
public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
if (modality == TYPE_FINGERPRINT) {
updateUdfpsController();
}
public void onEnrollmentsChanged() {
updateUdfpsController();
}
};
}

View File

@@ -16,8 +16,6 @@
package com.android.systemui.doze;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_QUICK_PICKUP;
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS;
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
@@ -31,7 +29,6 @@ import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.display.AmbientDisplayConfiguration;
import android.net.Uri;
import android.os.Handler;
@@ -838,17 +835,13 @@ public class DozeSensors {
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
if (modality == TYPE_FINGERPRINT) {
updateUdfpsEnrolled();
}
public void onAllAuthenticatorsRegistered() {
updateUdfpsEnrolled();
}
@Override
public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
if (modality == TYPE_FINGERPRINT) {
updateUdfpsEnrolled();
}
public void onEnrollmentsChanged() {
updateUdfpsEnrolled();
}
private void updateUdfpsEnrolled() {

View File

@@ -16,7 +16,6 @@
package com.android.keyguard;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
@@ -1007,7 +1006,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
// WHEN udfps is now enrolled
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
callback.onEnrollmentsChanged(TYPE_FINGERPRINT);
callback.onEnrollmentsChanged();
// THEN isUdfspEnrolled is TRUE
assertThat(mKeyguardUpdateMonitor.isUdfpsEnrolled()).isTrue();

View File

@@ -60,9 +60,6 @@ import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorProperties;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -157,9 +154,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private InteractionJankMonitor mInteractionJankMonitor;
@Captor
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mFpAuthenticatorsRegisteredCaptor;
@Captor
ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
@Captor
ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
@Captor
@@ -198,38 +193,25 @@ public class AuthControllerTest extends SysuiTestCase {
when(mDisplayManager.getStableDisplaySize()).thenReturn(new Point());
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
final List<ComponentInfoInternal> fpComponentInfo = List.of(
new ComponentInfoInternal("faceSensor" /* componentId */,
"vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
"00000001" /* serialNumber */, "" /* softwareVersion */));
final List<ComponentInfoInternal> faceComponentInfo = List.of(
new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
"" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
"vendor/version/revision" /* softwareVersion */));
final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
"vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
"00000001" /* serialNumber */, "" /* softwareVersion */));
componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
"" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
"vendor/version/revision" /* softwareVersion */));
final List<FingerprintSensorPropertiesInternal> fpProps = List.of(
new FingerprintSensorPropertiesInternal(
1 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
fpComponentInfo,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequireHardwareAuthToken */));
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(fpProps);
final List<FaceSensorPropertiesInternal> faceProps = List.of(
new FaceSensorPropertiesInternal(
2 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
fpComponentInfo,
FaceSensorProperties.TYPE_RGB,
true /* supportsFaceDetection */,
true /* supportsSelfIllumination */,
true /* resetLockoutRequireHardwareAuthToken */));
when(mFaceManager.getSensorPropertiesInternal()).thenReturn(faceProps);
FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
1 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
componentInfo,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequireHardwareAuthToken */);
List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
props.add(prop);
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue,
mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager,
@@ -237,15 +219,12 @@ public class AuthControllerTest extends SysuiTestCase {
mAuthController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
mFpAuthenticatorsRegisteredCaptor.capture());
verify(mFaceManager).addAuthenticatorsRegisteredCallback(
mFaceAuthenticatorsRegisteredCaptor.capture());
mAuthenticatorsRegisteredCaptor.capture());
when(mStatusBarStateController.isDozing()).thenReturn(false);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(fpProps);
mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps);
mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props);
// Ensures that the operations posted on the handler get executed.
mTestableLooper.processAllMessages();
@@ -258,7 +237,6 @@ public class AuthControllerTest extends SysuiTestCase {
throws RemoteException {
// This test is sensitive to prior FingerprintManager interactions.
reset(mFingerprintManager);
reset(mFaceManager);
// This test requires an uninitialized AuthController.
AuthController authController = new TestableAuthController(mContextSpy, mExecution,
@@ -268,27 +246,21 @@ public class AuthControllerTest extends SysuiTestCase {
authController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
mFpAuthenticatorsRegisteredCaptor.capture());
verify(mFaceManager).addAuthenticatorsRegisteredCallback(
mFaceAuthenticatorsRegisteredCaptor.capture());
mAuthenticatorsRegisteredCaptor.capture());
mTestableLooper.processAllMessages();
verify(mFingerprintManager, never()).registerBiometricStateListener(any());
verify(mFaceManager, never()).registerBiometricStateListener(any());
mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
mTestableLooper.processAllMessages();
verify(mFingerprintManager).registerBiometricStateListener(any());
verify(mFaceManager).registerBiometricStateListener(any());
}
@Test
public void testDoesNotCrash_afterEnrollmentsChangedForUnknownSensor() throws RemoteException {
// This test is sensitive to prior FingerprintManager interactions.
reset(mFingerprintManager);
reset(mFaceManager);
// This test requires an uninitialized AuthController.
AuthController authController = new TestableAuthController(mContextSpy, mExecution,
@@ -298,25 +270,18 @@ public class AuthControllerTest extends SysuiTestCase {
authController.start();
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
mFpAuthenticatorsRegisteredCaptor.capture());
verify(mFaceManager).addAuthenticatorsRegisteredCallback(
mFaceAuthenticatorsRegisteredCaptor.capture());
mAuthenticatorsRegisteredCaptor.capture());
// Emulates a device with no authenticators (empty list).
mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
mTestableLooper.processAllMessages();
verify(mFingerprintManager).registerBiometricStateListener(
mBiometricStateCaptor.capture());
verify(mFaceManager).registerBiometricStateListener(
mBiometricStateCaptor.capture());
// Enrollments changed for an unknown sensor.
for (BiometricStateListener listener : mBiometricStateCaptor.getAllValues()) {
listener.onEnrollmentsChanged(0 /* userId */,
0xbeef /* sensorId */, true /* hasEnrollments */);
}
mBiometricStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */,
0xbeef /* sensorId */, true /* hasEnrollments */);
mTestableLooper.processAllMessages();
// Nothing should crash.
@@ -862,3 +827,4 @@ public class AuthControllerTest extends SysuiTestCase {
}
}
}

View File

@@ -16,8 +16,6 @@
package com.android.systemui.doze;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_TAP;
import static com.android.systemui.doze.DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS;
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
@@ -414,7 +412,7 @@ public class DozeSensorsTest extends SysuiTestCase {
// WHEN enrollment changes to TRUE
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
mAuthControllerCallback.onEnrollmentsChanged(TYPE_FINGERPRINT);
mAuthControllerCallback.onEnrollmentsChanged();
// THEN mConfigured = TRUE
assertTrue(triggerSensor.mConfigured);

View File

@@ -16,8 +16,6 @@
package com.android.systemui.keyguard;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
@@ -221,7 +219,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
Pair<Float, PointF> udfps = setupUdfps();
// WHEN all authenticators are registered
mAuthControllerCallback.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT);
mAuthControllerCallback.onAllAuthenticatorsRegistered();
mDelayableExecutor.runAllReady();
// THEN lock icon view location is updated with the same coordinates as auth controller vals

View File

@@ -1,61 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.util.proto.ProtoOutputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
/**
* Common attributes for all biometric service providers.
*
* @param <T> Internal settings type.
*/
public interface BiometricServiceProvider<T extends SensorPropertiesInternal> {
/** Checks if the specified sensor is owned by this provider. */
boolean containsSensor(int sensorId);
/** All sensor properties. */
@NonNull
List<T> getSensorProperties();
/** Properties for the given sensor id. */
@NonNull
T getSensorProperties(int sensorId);
boolean isHardwareDetected(int sensorId);
/** If the user has any enrollments for the given sensor. */
boolean hasEnrollments(int sensorId, int userId);
long getAuthenticatorId(int sensorId, int userId);
@LockoutTracker.LockoutMode
int getLockoutModeForUser(int sensorId, int userId);
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer);
void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
void dumpInternal(int sensorId, @NonNull PrintWriter pw);
}

View File

@@ -1,235 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.Handler;
import android.os.IInterface;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.ServiceThread;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
/**
* Container for all BiometricServiceProvider implementations.
*
* @param <T> The service provider type.
* @param <P> The internal properties type.
* @param <C> The registration callback for {@link #invokeRegisteredCallback(IInterface, List)}.
*/
public abstract class BiometricServiceRegistry<T extends BiometricServiceProvider<P>,
P extends SensorPropertiesInternal,
C extends IInterface> {
private static final String TAG = "BiometricServiceRegistry";
// Volatile so they can be read without a lock once all services are registered.
// But, ideally remove this and provide immutable copies via the callback instead.
@Nullable
private volatile List<T> mServiceProviders;
@Nullable
private volatile List<P> mAllProps;
@NonNull
private final Supplier<IBiometricService> mBiometricServiceSupplier;
@NonNull
private final RemoteCallbackList<C> mRegisteredCallbacks = new RemoteCallbackList<>();
public BiometricServiceRegistry(@NonNull Supplier<IBiometricService> biometricSupplier) {
mBiometricServiceSupplier = biometricSupplier;
}
/**
* Register an implementation by creating a new authenticator and initializing it via
* {@link IBiometricService#registerAuthenticator(int, int, int, IBiometricAuthenticator)}
* using the given properties.
*
* @param service service to register with
* @param props internal properties to initialize the authenticator
*/
protected abstract void registerService(@NonNull IBiometricService service, @NonNull P props);
/**
* Invoke the callback to notify clients that all authenticators have been registered.
*
* @param callback callback to invoke
* @param allProps properties of all authenticators
*/
protected abstract void invokeRegisteredCallback(@NonNull C callback,
@NonNull List<P> allProps) throws RemoteException;
/**
* Register all authenticators in a background thread.
*
* @param serviceProvider Supplier function that will be invoked on the background thread.
*/
public void registerAll(Supplier<List<T>> serviceProvider) {
// Some HAL might not be started before the system service and will cause the code below
// to wait, and some of the operations below might take a significant amount of time to
// complete (calls to the HALs). To avoid blocking the rest of system server we put
// this on a background thread.
final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
true /* allowIo */);
thread.start();
final Handler handler = new Handler(thread.getLooper());
handler.post(() -> registerAllInBackground(serviceProvider));
thread.quitSafely();
}
/** Register authenticators now, only called by {@link #registerAll(Supplier).} */
@VisibleForTesting
public void registerAllInBackground(Supplier<List<T>> serviceProvider) {
List<T> providers = serviceProvider.get();
if (providers == null) {
providers = new ArrayList<>();
}
final IBiometricService biometricService = mBiometricServiceSupplier.get();
if (biometricService == null) {
throw new IllegalStateException("biometric service cannot be null");
}
// Register each sensor individually with BiometricService
final List<P> allProps = new ArrayList<>();
for (T provider : providers) {
final List<P> props = provider.getSensorProperties();
for (P prop : props) {
registerService(biometricService, prop);
}
allProps.addAll(props);
}
finishRegistration(providers, allProps);
}
private synchronized void finishRegistration(
@NonNull List<T> providers, @NonNull List<P> allProps) {
mServiceProviders = Collections.unmodifiableList(providers);
mAllProps = Collections.unmodifiableList(allProps);
broadcastAllAuthenticatorsRegistered();
}
/**
* Add a callback that will be invoked once the work from {@link #registerAll(Supplier)}
* has finished registering all providers (executes immediately if already done).
*
* @param callback registration callback
*/
public synchronized void addAllRegisteredCallback(@Nullable C callback) {
if (callback == null) {
Slog.e(TAG, "addAllRegisteredCallback, callback is null");
return;
}
final boolean registered = mRegisteredCallbacks.register(callback);
final boolean allRegistered = mServiceProviders != null;
if (registered && allRegistered) {
broadcastAllAuthenticatorsRegistered();
} else if (!registered) {
Slog.e(TAG, "addAllRegisteredCallback failed to register callback");
}
}
private synchronized void broadcastAllAuthenticatorsRegistered() {
final int n = mRegisteredCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
final C cb = mRegisteredCallbacks.getBroadcastItem(i);
try {
invokeRegisteredCallback(cb, mAllProps);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in broadcastAllAuthenticatorsRegistered", e);
} finally {
mRegisteredCallbacks.unregister(cb);
}
}
mRegisteredCallbacks.finishBroadcast();
}
/**
* Get a list of registered providers.
*
* Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
*/
@NonNull
public List<T> getProviders() {
return mServiceProviders != null ? mServiceProviders : Collections.emptyList();
}
/**
* Gets the provider for given sensor id or null if not registered.
*
* Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
*/
@Nullable
public T getProviderForSensor(int sensorId) {
if (mServiceProviders != null) {
for (T provider : mServiceProviders) {
if (provider.containsSensor(sensorId)) {
return provider;
}
}
}
return null;
}
/**
* For devices with only a single provider, returns that provider.
* If no providers, or multiple providers exist, returns null.
*
* Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
*/
@Nullable
public Pair<Integer, T> getSingleProvider() {
if (mAllProps == null || mAllProps.size() != 1) {
Slog.e(TAG, "Multiple sensors found: " + mAllProps.size());
return null;
}
final int sensorId = mAllProps.get(0).sensorId;
final T provider = getProviderForSensor(sensorId);
if (provider != null) {
return new Pair<>(sensorId, provider);
}
Slog.e(TAG, "Single sensor, but provider not found");
return null;
}
/**
* Get the properties for all providers.
*
* Undefined until {@link #registerAll(Supplier)} has fired the completion callback.
*/
@NonNull
public List<P> getAllProperties() {
return mAllProps != null ? mAllProps : Collections.emptyList();
}
}

View File

@@ -23,64 +23,32 @@ import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE;
import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_AUTH;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.IBiometricStateListener;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.Slog;
import com.android.server.biometrics.Utils;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A callback for receiving notifications about biometric sensor state changes.
*
* @param <T> service provider type
* @param <P> internal property type
*/
public class BiometricStateCallback<T extends BiometricServiceProvider<P>,
P extends SensorPropertiesInternal> implements ClientMonitorCallback {
public class BiometricStateCallback implements ClientMonitorCallback {
private static final String TAG = "BiometricStateCallback";
@NonNull
private final CopyOnWriteArrayList<IBiometricStateListener> mBiometricStateListeners =
new CopyOnWriteArrayList<>();
@NonNull
private final UserManager mUserManager;
@BiometricStateListener.State
private int mBiometricState;
@NonNull
private List<T> mProviders = List.of();
private final CopyOnWriteArrayList<IBiometricStateListener>
mBiometricStateListeners = new CopyOnWriteArrayList<>();
/**
* Create a new callback that must be {@link #start(List)}ed.
*
* @param userManager user manager
*/
public BiometricStateCallback(@NonNull UserManager userManager) {
private @BiometricStateListener.State int mBiometricState;
public BiometricStateCallback() {
mBiometricState = STATE_IDLE;
mUserManager = userManager;
}
/**
* This should be called when the service has been initialized and all providers are ready.
*
* @param allProviders all registered biometric service providers
*/
public synchronized void start(@NonNull List<T> allProviders) {
mProviders = Collections.unmodifiableList(allProviders);
broadcastCurrentEnrollmentState(null /* listener */);
}
/** Get the current state. */
@BiometricStateListener.State
public int getBiometricState() {
return mBiometricState;
}
@@ -152,43 +120,23 @@ public class BiometricStateCallback<T extends BiometricServiceProvider<P>,
}
/**
* Enables clients to register a BiometricStateListener. For example, this is used to forward
* fingerprint sensor state changes to SideFpsEventHandler.
*
* @param listener listener to register
* This should be invoked when:
* 1) Enrolled --> None-enrolled
* 2) None-enrolled --> enrolled
* 3) HAL becomes ready
* 4) Listener is registered
*/
public synchronized void registerBiometricStateListener(
@NonNull IBiometricStateListener listener) {
mBiometricStateListeners.add(listener);
broadcastCurrentEnrollmentState(listener);
}
private synchronized void broadcastCurrentEnrollmentState(
@Nullable IBiometricStateListener listener) {
for (T provider : mProviders) {
for (SensorPropertiesInternal prop : provider.getSensorProperties()) {
for (UserInfo userInfo : mUserManager.getAliveUsers()) {
final boolean enrolled = provider.hasEnrollments(prop.sensorId, userInfo.id);
if (listener != null) {
notifyEnrollmentStateChanged(
listener, userInfo.id, prop.sensorId, enrolled);
} else {
notifyAllEnrollmentStateChanged(
userInfo.id, prop.sensorId, enrolled);
}
}
}
}
}
private void notifyAllEnrollmentStateChanged(int userId, int sensorId,
public void notifyAllEnrollmentStateChanged(int userId, int sensorId,
boolean hasEnrollments) {
for (IBiometricStateListener listener : mBiometricStateListeners) {
notifyEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments);
}
}
private void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener,
/**
* Notifies the listener of enrollment state changes.
*/
public void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener,
int userId, int sensorId, boolean hasEnrollments) {
try {
listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments);
@@ -196,4 +144,14 @@ public class BiometricStateCallback<T extends BiometricServiceProvider<P>,
Slog.e(TAG, "Remote exception", e);
}
}
/**
* Enables clients to register a BiometricStateListener. For example, this is used to forward
* fingerprint sensor state changes to SideFpsEventHandler.
*
* @param listener
*/
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
mBiometricStateListeners.add(listener);
}
}

View File

@@ -17,18 +17,20 @@
package com.android.server.biometrics.sensors.face;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.MANAGE_FACE;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricStateListener;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
@@ -37,18 +39,18 @@ import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.Face;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.FaceServiceReceiver;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.NativeHandle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Pair;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -56,10 +58,10 @@ import android.view.Surface;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -86,10 +88,51 @@ public class FaceService extends SystemService {
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final LockPatternUtils mLockPatternUtils;
@NonNull
private final FaceServiceRegistry mRegistry;
private final List<ServiceProvider> mServiceProviders;
@Nullable
private ServiceProvider getProviderForSensor(int sensorId) {
for (ServiceProvider provider : mServiceProviders) {
if (provider.containsSensor(sensorId)) {
return provider;
}
}
return null;
}
/**
* For devices with only a single provider, returns that provider. If no providers, or multiple
* providers exist, returns null.
*/
@Nullable
private Pair<Integer, ServiceProvider> getSingleProvider() {
final List<FaceSensorPropertiesInternal> properties = getSensorProperties();
if (properties.size() != 1) {
Slog.e(TAG, "Multiple sensors found: " + properties.size());
return null;
}
// Theoretically we can just return the first provider, but maybe this is easier to
// understand.
final int sensorId = properties.get(0).sensorId;
for (ServiceProvider provider : mServiceProviders) {
if (provider.containsSensor(sensorId)) {
return new Pair<>(sensorId, provider);
}
}
Slog.e(TAG, "Single sensor, but provider not found");
return null;
}
@NonNull
private final BiometricStateCallback<ServiceProvider, FaceSensorPropertiesInternal>
mBiometricStateCallback;
private List<FaceSensorPropertiesInternal> getSensorProperties() {
final List<FaceSensorPropertiesInternal> properties = new ArrayList<>();
for (ServiceProvider provider : mServiceProviders) {
properties.addAll(provider.getSensorProperties());
}
return properties;
}
/**
* Receives the incoming binder calls from FaceManager.
@@ -99,7 +142,8 @@ public class FaceService extends SystemService {
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId);
@@ -112,8 +156,9 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) {
final ProtoOutputStream proto = new ProtoOutputStream();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider != null) {
provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
@@ -125,14 +170,16 @@ public class FaceService extends SystemService {
@Override // Binder call
public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(
String opPackageName) {
return mRegistry.getAllProperties();
return FaceService.this.getSensorProperties();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public FaceSensorPropertiesInternal getSensorProperties(int sensorId,
@NonNull String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId
+ ", caller: " + opPackageName);
@@ -146,7 +193,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void generateChallenge(IBinder token, int sensorId, int userId,
IFaceServiceReceiver receiver, String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
return;
@@ -159,7 +207,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName,
long challenge) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId);
return;
@@ -173,7 +222,8 @@ public class FaceService extends SystemService {
public long enroll(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures, Surface previewSurface, boolean debugConsent) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for enroll");
return -1;
@@ -195,7 +245,8 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
@Override // Binder call
public void cancelEnrollment(final IBinder token, long requestId) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelEnrollment");
return;
@@ -209,6 +260,7 @@ public class FaceService extends SystemService {
public long authenticate(final IBinder token, final long operationId, int userId,
final IFaceServiceReceiver receiver, final String opPackageName,
boolean isKeyguardBypassEnabled) {
// TODO(b/152413782): If the sensor supports face detect and the device is encrypted or
// lockdown, something wrong happened. See similar path in FingerprintService.
@@ -221,7 +273,7 @@ public class FaceService extends SystemService {
// permission.
final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName);
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for authenticate");
return -1;
@@ -249,7 +301,7 @@ public class FaceService extends SystemService {
return -1;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFace");
return -1;
@@ -266,7 +318,8 @@ public class FaceService extends SystemService {
IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
int cookie, boolean allowBackgroundAuthentication) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
@@ -283,7 +336,8 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void startPreparedClient(int sensorId, int cookie) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
@@ -296,7 +350,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void cancelAuthentication(final IBinder token, final String opPackageName,
final long requestId) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthentication");
return;
@@ -315,7 +370,7 @@ public class FaceService extends SystemService {
return;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelFaceDetect");
return;
@@ -328,7 +383,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void cancelAuthenticationFromService(int sensorId, final IBinder token,
final String opPackageName, final long requestId) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
@@ -341,7 +397,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void remove(final IBinder token, final int faceId, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for remove");
return;
@@ -355,6 +412,7 @@ public class FaceService extends SystemService {
@Override // Binder call
public void removeAll(final IBinder token, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
final FaceServiceReceiver internalReceiver = new FaceServiceReceiver() {
int sensorsFinishedRemoving = 0;
final int numSensors = getSensorPropertiesInternal(
@@ -374,7 +432,7 @@ public class FaceService extends SystemService {
// This effectively iterates through all sensors, but has to do so by finding all
// sensors under each provider.
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
List<FaceSensorPropertiesInternal> props = provider.getSensorProperties();
for (FaceSensorPropertiesInternal prop : props) {
provider.scheduleRemoveAll(prop.sensorId, token, userId, internalReceiver,
@@ -409,27 +467,27 @@ public class FaceService extends SystemService {
try {
if (args.length > 1 && "--proto".equals(args[0]) && "--state".equals(args[1])) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.dumpProtoState(props.sensorId, proto, false);
}
}
proto.flush();
} else if (args.length > 0 && "--proto".equals(args[0])) {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.dumpProtoMetrics(props.sensorId, fd);
}
}
} else if (args.length > 1 && "--hal".equals(args[0])) {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.dumpHal(props.sensorId, fd,
Arrays.copyOfRange(args, 1, args.length, args.getClass()));
}
}
} else {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
pw.println("Dumping for sensorId: " + props.sensorId
+ ", provider: " + provider.getClass().getSimpleName());
@@ -446,9 +504,10 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public boolean isHardwareDetected(int sensorId, String opPackageName) {
final long token = Binder.clearCallingIdentity();
try {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
@@ -462,11 +521,12 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName) {
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName);
return Collections.emptyList();
@@ -478,11 +538,12 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public boolean hasEnrolledFaces(int sensorId, int userId, String opPackageName) {
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for hasEnrolledFaces, caller: " + opPackageName);
return false;
@@ -494,7 +555,8 @@ public class FaceService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
@@ -507,7 +569,8 @@ public class FaceService extends SystemService {
@Override
public void invalidateAuthenticatorId(int sensorId, int userId,
IInvalidationCallback callback) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for invalidateAuthenticatorId");
return;
@@ -519,7 +582,7 @@ public class FaceService extends SystemService {
@Override // Binder call
public long getAuthenticatorId(int sensorId, int userId) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
@@ -532,7 +595,8 @@ public class FaceService extends SystemService {
@Override // Binder call
public void resetLockout(IBinder token, int sensorId, int userId, byte[] hardwareAuthToken,
String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
@@ -546,7 +610,8 @@ public class FaceService extends SystemService {
public void setFeature(final IBinder token, int userId, int feature, boolean enabled,
final byte[] hardwareAuthToken, IFaceServiceReceiver receiver,
final String opPackageName) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for setFeature");
return;
@@ -560,7 +625,8 @@ public class FaceService extends SystemService {
@Override
public void getFeature(final IBinder token, int userId, int feature,
IFaceServiceReceiver receiver, final String opPackageName) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for getFeature");
return;
@@ -570,14 +636,18 @@ public class FaceService extends SystemService {
new ClientMonitorCallbackConverter(receiver), opPackageName);
}
private List<ServiceProvider> getAidlProviders() {
final List<ServiceProvider> providers = new ArrayList<>();
private void addHidlProviders(@NonNull List<FaceSensorPropertiesInternal> hidlSensors) {
for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) {
mServiceProviders.add(
Face10.newInstance(getContext(), hidlSensor, mLockoutResetDispatcher));
}
}
private void addAidlProviders() {
final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
if (instances == null || instances.length == 0) {
return providers;
return;
}
for (String instance : instances) {
final String fqName = IFace.DESCRIPTOR + "/" + instance;
final IFace face = IFace.Stub.asInterface(
@@ -590,41 +660,53 @@ public class FaceService extends SystemService {
final SensorProps[] props = face.getSensorProps();
final FaceProvider provider = new FaceProvider(getContext(), props, instance,
mLockoutResetDispatcher, BiometricContext.getInstance(getContext()));
providers.add(provider);
mServiceProviders.add(provider);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
}
return providers;
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void registerAuthenticators(
@NonNull List<FaceSensorPropertiesInternal> hidlSensors) {
mRegistry.registerAll(() -> {
final List<ServiceProvider> providers = new ArrayList<>();
for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) {
providers.add(
Face10.newInstance(getContext(), hidlSensor, mLockoutResetDispatcher));
// Some HAL might not be started before the system service and will cause the code below
// to wait, and some of the operations below might take a significant amount of time to
// complete (calls to the HALs). To avoid blocking the rest of system server we put
// this on a background thread.
final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
true /* allowIo */);
thread.start();
final Handler handler = new Handler(thread.getLooper());
handler.post(() -> {
addHidlProviders(hidlSensors);
addAidlProviders();
final IBiometricService biometricService = IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE));
// Register each sensor individually with BiometricService
for (ServiceProvider provider : mServiceProviders) {
final List<FaceSensorPropertiesInternal> props = provider.getSensorProperties();
for (FaceSensorPropertiesInternal prop : props) {
final int sensorId = prop.sensorId;
final @BiometricManager.Authenticators.Types int strength =
Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
final FaceAuthenticator authenticator = new FaceAuthenticator(
mServiceWrapper, sensorId);
try {
biometricService.registerAuthenticator(sensorId, TYPE_FACE, strength,
authenticator);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
}
}
}
providers.addAll(getAidlProviders());
return providers;
});
}
@Override
public void addAuthenticatorsRegisteredCallback(
IFaceAuthenticatorsRegisteredCallback callback) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
mRegistry.addAllRegisteredCallback(callback);
}
@Override
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
mBiometricStateCallback.registerBiometricStateListener(listener);
}
}
public FaceService(Context context) {
@@ -632,16 +714,7 @@ public class FaceService extends SystemService {
mServiceWrapper = new FaceServiceWrapper();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
mRegistry = new FaceServiceRegistry(mServiceWrapper,
() -> IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)));
mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(List<FaceSensorPropertiesInternal> sensors) {
mBiometricStateCallback.start(mRegistry.getProviders());
}
});
mServiceProviders = new ArrayList<>();
}
@Override
@@ -679,7 +752,7 @@ public class FaceService extends SystemService {
if (Utils.isVirtualEnabled(getContext())) {
Slog.i(TAG, "Sync virtual enrollments");
final int userId = ActivityManager.getCurrentUser();
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */,
true /* favorHalEnrollments */);

View File

@@ -1,71 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors.face;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.IBiometricService;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceService;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BiometricServiceRegistry;
import java.util.List;
import java.util.function.Supplier;
/** Registry for {@link IFaceService} providers. */
public class FaceServiceRegistry extends BiometricServiceRegistry<ServiceProvider,
FaceSensorPropertiesInternal, IFaceAuthenticatorsRegisteredCallback> {
private static final String TAG = "FaceServiceRegistry";
@NonNull
private final IFaceService mService;
/** Creates a new registry tied to the given service. */
public FaceServiceRegistry(@NonNull IFaceService service,
@Nullable Supplier<IBiometricService> biometricSupplier) {
super(biometricSupplier);
mService = service;
}
@Override
protected void registerService(@NonNull IBiometricService service,
@NonNull FaceSensorPropertiesInternal props) {
@BiometricManager.Authenticators.Types final int strength =
Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength);
try {
service.registerAuthenticator(props.sensorId, TYPE_FACE, strength,
new FaceAuthenticator(mService, props.sensorId));
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId);
}
}
@Override
protected void invokeRegisteredCallback(@NonNull IFaceAuthenticatorsRegisteredCallback callback,
@NonNull List<FaceSensorPropertiesInternal> allProps) throws RemoteException {
callback.onAllAuthenticatorsRegistered(allProps);
}
}

View File

@@ -26,13 +26,15 @@ import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceServiceReceiver;
import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
import android.view.Surface;
import com.android.server.biometrics.sensors.BiometricServiceProvider;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
/**
@@ -54,11 +56,24 @@ import java.util.List;
* to check (e.g. via {@link FaceManager#getSensorPropertiesInternal()}) that the code path isn't
* taken. ServiceProviders will provide a no-op for unsupported operations to fail safely.
*/
public interface ServiceProvider extends BiometricServiceProvider<FaceSensorPropertiesInternal> {
public interface ServiceProvider {
/**
* Checks if the specified sensor is owned by this provider.
*/
boolean containsSensor(int sensorId);
@NonNull
List<FaceSensorPropertiesInternal> getSensorProperties();
@NonNull
FaceSensorPropertiesInternal getSensorProperties(int sensorId);
@NonNull
List<Face> getEnrolledFaces(int sensorId, int userId);
@LockoutTracker.LockoutMode
int getLockoutModeForUser(int sensorId, int userId);
/**
* Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to be
* invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
@@ -69,6 +84,10 @@ public interface ServiceProvider extends BiometricServiceProvider<FaceSensorProp
+ " this method");
}
long getAuthenticatorId(int sensorId, int userId);
boolean isHardwareDetected(int sensorId);
void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
@NonNull IFaceServiceReceiver receiver, String opPackageName);
@@ -123,6 +142,13 @@ public interface ServiceProvider extends BiometricServiceProvider<FaceSensorProp
void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback, boolean favorHalEnrollments);
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer);
void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
void dumpInternal(int sensorId, @NonNull PrintWriter pw);
@NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName);

View File

@@ -284,11 +284,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
return FaceUtils.getInstance(sensorId).getBiometricsForUser(mContext, userId);
}
@Override
public boolean hasEnrollments(int sensorId, int userId) {
return !getEnrolledFaces(sensorId, userId).isEmpty();
}
@Override
public void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
@NonNull IInvalidationCallback callback) {

View File

@@ -483,11 +483,6 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
return FaceUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId);
}
@Override
public boolean hasEnrollments(int sensorId, int userId) {
return !getEnrolledFaces(sensorId, userId).isEmpty();
}
@Override
@LockoutTracker.LockoutMode
public int getLockoutModeForUser(int sensorId, int userId) {

View File

@@ -17,11 +17,14 @@
package com.android.server.biometrics.sensors.fingerprint;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
import static android.Manifest.permission.TEST_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR;
@@ -33,6 +36,8 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -60,6 +65,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -73,9 +79,11 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
@@ -107,32 +115,74 @@ public class FingerprintService extends SystemService {
protected static final String TAG = "FingerprintService";
private final Object mLock = new Object();
private final AppOpsManager mAppOps;
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
@NonNull
private final BiometricContext mBiometricContext;
@NonNull
private final Supplier<String[]> mAidlInstanceNameSupplier;
@NonNull
private final Function<String, IFingerprint> mIFingerprintProvider;
@NonNull
private final BiometricStateCallback<ServiceProvider, FingerprintSensorPropertiesInternal>
mBiometricStateCallback;
@NonNull
private final Handler mHandler;
@NonNull
private final FingerprintServiceRegistry mRegistry;
@NonNull private final List<ServiceProvider> mServiceProviders;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final Handler mHandler;
@NonNull private final BiometricContext mBiometricContext;
@NonNull private final Supplier<IBiometricService> mBiometricServiceSupplier;
@NonNull private final Function<String, IFingerprint> mIFingerprintProvider;
/** Receives the incoming binder calls from FingerprintManager. */
@VisibleForTesting
final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() {
@GuardedBy("mLock")
@NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback>
mAuthenticatorsRegisteredCallbacks;
@GuardedBy("mLock")
@NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps;
/**
* Registers BiometricStateListener in list stored by FingerprintService
* @param listener new BiometricStateListener being added
*/
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
mBiometricStateCallback.registerBiometricStateListener(listener);
broadcastCurrentEnrollmentState(listener);
}
/**
* @param listener if non-null, notifies only this listener. if null, notifies all listeners
* in {@link BiometricStateCallback}. This is slightly ugly, but reduces
* redundant code.
*/
private void broadcastCurrentEnrollmentState(@Nullable IBiometricStateListener listener) {
final UserManager um = UserManager.get(getContext());
synchronized (mLock) {
// Update the new listener with current state of all sensors
for (FingerprintSensorPropertiesInternal prop : mSensorProps) {
final ServiceProvider provider = getProviderForSensor(prop.sensorId);
for (UserInfo userInfo : um.getAliveUsers()) {
final boolean enrolled = !provider
.getEnrolledFingerprints(prop.sensorId, userInfo.id).isEmpty();
// Defer this work and allow the loop to release the lock sooner
mHandler.post(() -> {
if (listener != null) {
mBiometricStateCallback.notifyEnrollmentStateChanged(
listener, userInfo.id, prop.sensorId, enrolled);
} else {
mBiometricStateCallback.notifyAllEnrollmentStateChanged(
userInfo.id, prop.sensorId, enrolled);
}
});
}
}
}
}
/**
* Receives the incoming binder calls from FingerprintManager.
*/
private final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() {
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId);
@@ -145,8 +195,9 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) {
final ProtoOutputStream proto = new ProtoOutputStream();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider != null) {
provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
@@ -161,14 +212,16 @@ public class FingerprintService extends SystemService {
!= PackageManager.PERMISSION_GRANTED) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
return mRegistry.getAllProperties();
return FingerprintService.this.getSensorProperties();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId,
@NonNull String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId
+ ", caller: " + opPackageName);
@@ -181,7 +234,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void generateChallenge(IBinder token, int sensorId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
return;
@@ -194,7 +248,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName,
long challenge) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId);
return;
@@ -209,7 +264,8 @@ public class FingerprintService extends SystemService {
public long enroll(final IBinder token, @NonNull final byte[] hardwareAuthToken,
final int userId, final IFingerprintServiceReceiver receiver,
final String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for enroll");
return -1;
@@ -222,7 +278,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public void cancelEnrollment(final IBinder token, long requestId) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelEnrollment");
return;
@@ -282,10 +339,10 @@ public class FingerprintService extends SystemService {
final Pair<Integer, ServiceProvider> provider;
if (sensorId == FingerprintManager.SENSOR_ID_ANY) {
provider = mRegistry.getSingleProvider();
provider = getSingleProvider();
} else {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
provider = new Pair<>(sensorId, mRegistry.getProviderForSensor(sensorId));
provider = new Pair<>(sensorId, getProviderForSensor(sensorId));
}
if (provider == null) {
Slog.w(TAG, "Null provider for authenticate");
@@ -317,6 +374,7 @@ public class FingerprintService extends SystemService {
final IFingerprintServiceReceiver receiver,
final String opPackageName,
boolean ignoreEnrollmentState) throws PackageManager.NameNotFoundException {
final Context context = getUiContext();
final Context promptContext = context.createPackageContextAsUser(
opPackageName, 0 /* flags */, UserHandle.getUserHandleForUid(uId));
@@ -410,7 +468,7 @@ public class FingerprintService extends SystemService {
return -1;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFingerprint");
return -1;
@@ -426,7 +484,8 @@ public class FingerprintService extends SystemService {
public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
long requestId, int cookie, boolean allowBackgroundAuthentication) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
@@ -442,7 +501,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
@Override // Binder call
public void startPreparedClient(int sensorId, int cookie) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
@@ -472,7 +532,7 @@ public class FingerprintService extends SystemService {
return;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthentication");
return;
@@ -493,7 +553,7 @@ public class FingerprintService extends SystemService {
// For IBiometricsFingerprint2.1, cancelling fingerprint detect is the same as
// cancelling authentication.
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelFingerprintDetect");
return;
@@ -506,9 +566,11 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
final String opPackageName, final long requestId) {
Slog.d(TAG, "cancelAuthenticationFromService, sensorId: " + sensorId);
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
@@ -521,7 +583,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void remove(final IBinder token, final int fingerId, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for remove");
return;
@@ -554,7 +617,7 @@ public class FingerprintService extends SystemService {
// This effectively iterates through all sensors, but has to do so by finding all
// sensors under each provider.
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
List<FingerprintSensorPropertiesInternal> props = provider.getSensorProperties();
for (FingerprintSensorPropertiesInternal prop : props) {
provider.scheduleRemoveAll(prop.sensorId, token, internalReceiver, userId,
@@ -589,7 +652,7 @@ public class FingerprintService extends SystemService {
try {
if (args.length > 1 && "--proto".equals(args[0]) && "--state".equals(args[1])) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
provider.dumpProtoState(props.sensorId, proto, false);
@@ -597,14 +660,14 @@ public class FingerprintService extends SystemService {
}
proto.flush();
} else if (args.length > 0 && "--proto".equals(args[0])) {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
provider.dumpProtoMetrics(props.sensorId, fd);
}
}
} else {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
pw.println("Dumping for sensorId: " + props.sensorId
@@ -635,7 +698,7 @@ public class FingerprintService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetectedDeprecated, caller: "
+ opPackageName);
@@ -650,7 +713,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public boolean isHardwareDetected(int sensorId, String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
@@ -666,7 +730,7 @@ public class FingerprintService extends SystemService {
return;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for rename");
return;
@@ -717,7 +781,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for hasEnrolledFingerprints, caller: " + opPackageName);
return false;
@@ -729,7 +794,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
@@ -741,7 +807,8 @@ public class FingerprintService extends SystemService {
@Override
public void invalidateAuthenticatorId(int sensorId, int userId,
IInvalidationCallback callback) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for invalidateAuthenticatorId");
return;
@@ -752,7 +819,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public long getAuthenticatorId(int sensorId, int userId) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
@@ -764,7 +832,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void resetLockout(IBinder token, int sensorId, int userId,
@Nullable byte[] hardwareAuthToken, String opPackageName) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
@@ -795,38 +864,55 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void registerAuthenticators(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
mRegistry.registerAll(() -> {
final List<ServiceProvider> providers = new ArrayList<>();
providers.addAll(getHidlProviders(hidlSensors));
// Some HAL might not be started before the system service and will cause the code below
// to wait, and some of the operations below might take a significant amount of time to
// complete (calls to the HALs). To avoid blocking the rest of system server we put
// this on a background thread.
final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
true /* allowIo */);
thread.start();
final Handler handler = new Handler(thread.getLooper());
handler.post(() -> {
List<String> aidlSensors = new ArrayList<>();
final String[] instances = mAidlInstanceNameSupplier.get();
final String[] instances =
ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR);
if (instances != null) {
aidlSensors.addAll(Lists.newArrayList(instances));
}
providers.addAll(getAidlProviders(
Utils.filterAvailableHalInstances(getContext(), aidlSensors)));
return providers;
registerAuthenticatorsForService(aidlSensors, hidlSensors);
});
thread.quitSafely();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void addAuthenticatorsRegisteredCallback(
IFingerprintAuthenticatorsRegisteredCallback callback) {
mRegistry.addAllRegisteredCallback(callback);
}
if (callback == null) {
Slog.e(TAG, "addAuthenticatorsRegisteredCallback, callback is null");
return;
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
mBiometricStateCallback.registerBiometricStateListener(listener);
final boolean registered;
final boolean hasSensorProps;
synchronized (mLock) {
registered = mAuthenticatorsRegisteredCallbacks.register(callback);
hasSensorProps = !mSensorProps.isEmpty();
}
if (registered && hasSensorProps) {
broadcastAllAuthenticatorsRegistered();
} else if (!registered) {
Slog.e(TAG, "addAuthenticatorsRegisteredCallback failed to register callback");
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onPointerDown(long requestId, int sensorId, int x, int y,
float minor, float major) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
return;
@@ -837,7 +923,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onPointerUp(long requestId, int sensorId) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
return;
@@ -848,7 +935,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onUiReady(long requestId, int sensorId) {
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
return;
@@ -859,7 +947,8 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
provider.setUdfpsOverlayController(controller);
}
}
@@ -867,15 +956,22 @@ public class FingerprintService extends SystemService {
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
provider.setSidefpsController(controller);
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
FingerprintService.this.registerBiometricStateListener(listener);
}
@Override
public void onPowerPressed() {
for (ServiceProvider provider : mRegistry.getProviders()) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
for (ServiceProvider provider : mServiceProviders) {
provider.onPowerPressed();
}
}
@@ -885,7 +981,6 @@ public class FingerprintService extends SystemService {
this(context, BiometricContext.getInstance(context),
() -> IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
() -> ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR),
(fqName) -> IFingerprint.Stub.asInterface(
Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName))));
}
@@ -893,34 +988,61 @@ public class FingerprintService extends SystemService {
@VisibleForTesting
FingerprintService(Context context,
BiometricContext biometricContext,
Supplier<IBiometricService> biometricServiceSupplier,
Supplier<String[]> aidlInstanceNameSupplier,
Supplier<IBiometricService> biometricServiceProvider,
Function<String, IFingerprint> fingerprintProvider) {
super(context);
mBiometricContext = biometricContext;
mAidlInstanceNameSupplier = aidlInstanceNameSupplier;
mBiometricServiceSupplier = biometricServiceProvider;
mIFingerprintProvider = fingerprintProvider;
mAppOps = context.getSystemService(AppOpsManager.class);
mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
mServiceProviders = new ArrayList<>();
mBiometricStateCallback = new BiometricStateCallback();
mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>();
mSensorProps = new ArrayList<>();
mHandler = new Handler(Looper.getMainLooper());
mRegistry = new FingerprintServiceRegistry(mServiceWrapper, biometricServiceSupplier);
mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
mBiometricStateCallback.start(mRegistry.getProviders());
}
});
}
@NonNull
private List<ServiceProvider> getHidlProviders(
@VisibleForTesting
void registerAuthenticatorsForService(@NonNull List<String> aidlInstanceNames,
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
final List<ServiceProvider> providers = new ArrayList<>();
addHidlProviders(hidlSensors);
addAidlProviders(Utils.filterAvailableHalInstances(getContext(), aidlInstanceNames));
final IBiometricService biometricService = mBiometricServiceSupplier.get();
// Register each sensor individually with BiometricService
for (ServiceProvider provider : mServiceProviders) {
final List<FingerprintSensorPropertiesInternal> props =
provider.getSensorProperties();
for (FingerprintSensorPropertiesInternal prop : props) {
final int sensorId = prop.sensorId;
@BiometricManager.Authenticators.Types final int strength =
Utils.propertyStrengthToAuthenticatorStrength(prop.sensorStrength);
final FingerprintAuthenticator authenticator = new FingerprintAuthenticator(
mServiceWrapper, sensorId);
try {
biometricService.registerAuthenticator(sensorId, TYPE_FINGERPRINT,
strength, authenticator);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId);
}
}
}
synchronized (mLock) {
for (ServiceProvider provider : mServiceProviders) {
mSensorProps.addAll(provider.getSensorProperties());
}
}
broadcastCurrentEnrollmentState(null); // broadcasts to all listeners
broadcastAllAuthenticatorsRegistered();
}
private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) {
for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) {
final Fingerprint21 fingerprint21;
if ((Build.IS_USERDEBUG || Build.IS_ENG)
@@ -937,16 +1059,11 @@ public class FingerprintService extends SystemService {
mBiometricStateCallback, hidlSensor, mHandler,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
providers.add(fingerprint21);
mServiceProviders.add(fingerprint21);
}
return providers;
}
@NonNull
private List<ServiceProvider> getAidlProviders(@NonNull List<String> instances) {
final List<ServiceProvider> providers = new ArrayList<>();
private void addAidlProviders(List<String> instances) {
for (String instance : instances) {
final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
final IFingerprint fp = mIFingerprintProvider.apply(fqName);
@@ -958,7 +1075,7 @@ public class FingerprintService extends SystemService {
mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
mBiometricContext);
Slog.i(TAG, "Adding AIDL provider: " + fqName);
providers.add(provider);
mServiceProviders.add(provider);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
@@ -966,8 +1083,38 @@ public class FingerprintService extends SystemService {
Slog.e(TAG, "Unable to get declared service: " + fqName);
}
}
}
return providers;
// Notifies the callbacks that all of the authenticators have been registered and removes the
// invoked callbacks from the callback list.
private void broadcastAllAuthenticatorsRegistered() {
// Make a local copy of the data so it can be used outside of the synchronized block when
// making Binder calls.
final List<IFingerprintAuthenticatorsRegisteredCallback> callbacks = new ArrayList<>();
final List<FingerprintSensorPropertiesInternal> props;
synchronized (mLock) {
if (!mSensorProps.isEmpty()) {
props = new ArrayList<>(mSensorProps);
} else {
Slog.e(TAG, "mSensorProps is empty");
return;
}
final int n = mAuthenticatorsRegisteredCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
final IFingerprintAuthenticatorsRegisteredCallback cb =
mAuthenticatorsRegisteredCallbacks.getBroadcastItem(i);
callbacks.add(cb);
mAuthenticatorsRegisteredCallbacks.unregister(cb);
}
mAuthenticatorsRegisteredCallbacks.finishBroadcast();
}
for (IFingerprintAuthenticatorsRegisteredCallback cb : callbacks) {
try {
cb.onAllAuthenticatorsRegistered(props);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in onAllAuthenticatorsRegistered", e);
}
}
}
@Override
@@ -975,9 +1122,51 @@ public class FingerprintService extends SystemService {
publishBinderService(Context.FINGERPRINT_SERVICE, mServiceWrapper);
}
@Nullable
private ServiceProvider getProviderForSensor(int sensorId) {
for (ServiceProvider provider : mServiceProviders) {
if (provider.containsSensor(sensorId)) {
return provider;
}
}
return null;
}
/**
* For devices with only a single provider, returns that provider. If multiple providers,
* returns the first one. If no providers, returns null.
*/
@Nullable
private Pair<Integer, ServiceProvider> getSingleProvider() {
final List<FingerprintSensorPropertiesInternal> properties = getSensorProperties();
if (properties.isEmpty()) {
Slog.e(TAG, "No providers found");
return null;
}
// Theoretically we can just return the first provider, but maybe this is easier to
// understand.
final int sensorId = properties.get(0).sensorId;
for (ServiceProvider provider : mServiceProviders) {
if (provider.containsSensor(sensorId)) {
return new Pair<>(sensorId, provider);
}
}
Slog.e(TAG, "Provider not found");
return null;
}
@NonNull
private List<FingerprintSensorPropertiesInternal> getSensorProperties() {
synchronized (mLock) {
return mSensorProps;
}
}
@NonNull
private List<Fingerprint> getEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for getEnrolledFingerprintsDeprecated, caller: "
+ opPackageName);
@@ -1040,7 +1229,7 @@ public class FingerprintService extends SystemService {
if (Utils.isVirtualEnabled(getContext())) {
Slog.i(TAG, "Sync virtual enrollments");
final int userId = ActivityManager.getCurrentUser();
for (ServiceProvider provider : mRegistry.getProviders()) {
for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.scheduleInternalCleanup(props.sensorId, userId, null /* callback */,
true /* favorHalEnrollments */);

View File

@@ -1,72 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors.fingerprint;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.IBiometricService;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IFingerprintService;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BiometricServiceRegistry;
import java.util.List;
import java.util.function.Supplier;
/** Registry for {@link IFingerprintService} providers. */
public class FingerprintServiceRegistry extends BiometricServiceRegistry<ServiceProvider,
FingerprintSensorPropertiesInternal, IFingerprintAuthenticatorsRegisteredCallback> {
private static final String TAG = "FingerprintServiceRegistry";
@NonNull
private final IFingerprintService mService;
/** Creates a new registry tied to the given service. */
public FingerprintServiceRegistry(@NonNull IFingerprintService service,
@Nullable Supplier<IBiometricService> biometricSupplier) {
super(biometricSupplier);
mService = service;
}
@Override
protected void registerService(@NonNull IBiometricService service,
@NonNull FingerprintSensorPropertiesInternal props) {
@BiometricManager.Authenticators.Types final int strength =
Utils.propertyStrengthToAuthenticatorStrength(props.sensorStrength);
try {
service.registerAuthenticator(props.sensorId, TYPE_FINGERPRINT, strength,
new FingerprintAuthenticator(mService, props.sensorId));
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when registering sensorId: " + props.sensorId);
}
}
@Override
protected void invokeRegisteredCallback(
@NonNull IFingerprintAuthenticatorsRegisteredCallback callback,
@NonNull List<FingerprintSensorPropertiesInternal> allProps) throws RemoteException {
callback.onAllAuthenticatorsRegistered(allProps);
}
}

View File

@@ -28,11 +28,14 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
import com.android.server.biometrics.sensors.BiometricServiceProvider;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
/**
@@ -56,8 +59,23 @@ import java.util.List;
* fail safely.
*/
@SuppressWarnings("deprecation")
public interface ServiceProvider extends
BiometricServiceProvider<FingerprintSensorPropertiesInternal> {
public interface ServiceProvider {
/**
* Checks if the specified sensor is owned by this provider.
*/
boolean containsSensor(int sensorId);
@NonNull
List<FingerprintSensorPropertiesInternal> getSensorProperties();
/**
* Returns the internal properties of the specified sensor, if owned by this provider.
*
* @param sensorId The ID of a fingerprint sensor, or -1 for any sensor.
* @return An object representing the internal properties of the specified sensor.
*/
@Nullable
FingerprintSensorPropertiesInternal getSensorProperties(int sensorId);
void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken);
@@ -108,11 +126,16 @@ public interface ServiceProvider extends
void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback, boolean favorHalEnrollments);
boolean isHardwareDetected(int sensorId);
void rename(int sensorId, int fingerId, int userId, @NonNull String name);
@NonNull
List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId);
@LockoutTracker.LockoutMode
int getLockoutModeForUser(int sensorId, int userId);
/**
* Requests for the authenticatorId (whose source of truth is in the TEE or equivalent) to
* be invalidated. See {@link com.android.server.biometrics.sensors.InvalidationRequesterClient}
@@ -120,6 +143,7 @@ public interface ServiceProvider extends
void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
@NonNull IInvalidationCallback callback);
long getAuthenticatorId(int sensorId, int userId);
void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
@@ -137,6 +161,13 @@ public interface ServiceProvider extends
*/
void setSidefpsController(@NonNull ISidefpsController controller);
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer);
void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
void dumpInternal(int sensorId, @NonNull PrintWriter pw);
@NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName);

View File

@@ -564,11 +564,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
return FingerprintUtils.getInstance(sensorId).getBiometricsForUser(mContext, userId);
}
@Override
public boolean hasEnrollments(int sensorId, int userId) {
return !getEnrolledFingerprints(sensorId, userId).isEmpty();
}
@Override
public void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
@NonNull IInvalidationCallback callback) {

View File

@@ -788,11 +788,6 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
return FingerprintUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId);
}
@Override
public boolean hasEnrollments(int sensorId, int userId) {
return !getEnrolledFingerprints(sensorId, userId).isEmpty();
}
@Override
@LockoutTracker.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) {
return mLockoutTracker.getLockoutModeForUser(userId);

View File

@@ -1,165 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors.face;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.hardware.biometrics.IBiometricService;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.face.IFaceService;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@Presubmit
@SmallTest
public class FaceServiceRegistryTest {
private static final int SENSOR_ID_1 = 1;
private static final int SENSOR_ID_2 = 2;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
private IBiometricService mBiometricService;
@Mock
private IFaceService mFaceService;
@Mock
private ServiceProvider mProvider1;
@Mock
private ServiceProvider mProvider2;
@Captor
private ArgumentCaptor<Integer> mIdCaptor;
@Captor
private ArgumentCaptor<Integer> mStrengthCaptor;
private FaceSensorPropertiesInternal mProvider1Props;
private FaceSensorPropertiesInternal mProvider2Props;
private FaceServiceRegistry mRegistry;
@Before
public void setup() {
mProvider1Props = new FaceSensorPropertiesInternal(SENSOR_ID_1,
STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */,
List.of(), FaceSensorProperties.TYPE_RGB,
true /* supportsFace Detection */,
true /* supportsSelfIllumination */,
false /* resetLockoutRequiresHardwareAuthToken */);
mProvider2Props = new FaceSensorPropertiesInternal(SENSOR_ID_2,
STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
List.of(), FaceSensorProperties.TYPE_IR,
true /* supportsFace Detection */,
true /* supportsSelfIllumination */,
false /* resetLockoutRequiresHardwareAuthToken */);
when(mProvider1.getSensorProperties()).thenReturn(List.of(mProvider1Props));
when(mProvider1.containsSensor(eq(SENSOR_ID_1))).thenReturn(true);
when(mProvider2.getSensorProperties()).thenReturn(List.of(mProvider2Props));
when(mProvider2.containsSensor(eq(SENSOR_ID_2))).thenReturn(true);
mRegistry = new FaceServiceRegistry(mFaceService, () -> mBiometricService);
}
@Test
public void registersAllProviders() throws Exception {
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2);
assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props);
verify(mBiometricService, times(2)).registerAuthenticator(
mIdCaptor.capture(), eq(TYPE_FACE), mStrengthCaptor.capture(), any());
assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2);
assertThat(mStrengthCaptor.getAllValues())
.containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG);
}
@Test
public void getsProviderById() {
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
assertThat(mRegistry.getProviderForSensor(SENSOR_ID_2)).isSameInstanceAs(mProvider2);
assertThat(mRegistry.getProviderForSensor(500)).isNull();
}
@Test
public void getsSingleProvider() {
mRegistry.registerAllInBackground(() -> List.of(mProvider1));
assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1);
assertThat(mRegistry.getProviders()).containsExactly(mProvider1);
assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
}
@Test
public void registersListenerBeforeAllRegistered() {
final List<FaceSensorPropertiesInternal> all = new ArrayList<>();
mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FaceSensorPropertiesInternal> sensors) {
all.addAll(sensors);
}
});
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
}
@Test
public void registersListenerAfterAllRegistered() {
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
final List<FaceSensorPropertiesInternal> all = new ArrayList<>();
mRegistry.addAllRegisteredCallback(new IFaceAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FaceSensorPropertiesInternal> sensors) {
all.addAll(sensors);
}
});
assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
}
}

View File

@@ -16,8 +16,6 @@
package com.android.server.biometrics.sensors.fingerprint;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -26,72 +24,37 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricServiceProvider;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.List;
import org.mockito.MockitoAnnotations;
@Presubmit
@SmallTest
public class BiometricStateCallbackTest {
private static final int USER_ID = 10;
private static final int SENSOR_ID = 2;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
private BiometricStateCallback<FakeProvider, SensorPropertiesInternal> mCallback;
private BiometricStateCallback mCallback;
@Mock
private UserManager mUserManager;
@Mock
private BiometricStateListener mBiometricStateListener;
@Mock
private FakeProvider mFakeProvider;
private SensorPropertiesInternal mFakeProviderProps;
BiometricStateListener mBiometricStateListener;
@Before
public void setup() {
mFakeProviderProps = new SensorPropertiesInternal(SENSOR_ID, STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */, List.of(),
false /* resetLockoutRequiresHardwareAuthToken */,
false /* resetLockoutRequiresChallenge */);
when(mFakeProvider.getSensorProperties()).thenReturn(List.of(mFakeProviderProps));
when(mFakeProvider.getSensorProperties(eq(SENSOR_ID))).thenReturn(mFakeProviderProps);
when(mFakeProvider.hasEnrollments(eq(SENSOR_ID), eq(USER_ID))).thenReturn(true);
when(mUserManager.getAliveUsers()).thenReturn(
List.of(new UserInfo(USER_ID, "name", 0)));
MockitoAnnotations.initMocks(this);
mCallback = new BiometricStateCallback<>(mUserManager);
mCallback = new BiometricStateCallback();
mCallback.registerBiometricStateListener(mBiometricStateListener);
}
@Test
public void startNotifiesEnrollments() {
mCallback.start(List.of(mFakeProvider));
verify(mBiometricStateListener).onEnrollmentsChanged(eq(USER_ID), eq(SENSOR_ID), eq(true));
}
@Test
public void testNoEnrollmentsToEnrollments_callbackNotified() {
testEnrollmentCallback(true /* changed */, true /* isNowEnrolled */,
@@ -139,6 +102,4 @@ public class BiometricStateCallbackTest {
verify(mBiometricStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
anyBoolean());
}
private interface FakeProvider extends BiometricServiceProvider<SensorPropertiesInternal> {}
}

View File

@@ -1,161 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.biometrics.sensors.fingerprint;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_WEAK;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.hardware.biometrics.IBiometricService;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IFingerprintService;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@Presubmit
@SmallTest
public class FingerprintServiceRegistryTest {
private static final int SENSOR_ID_1 = 1;
private static final int SENSOR_ID_2 = 2;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
private IBiometricService mBiometricService;
@Mock
private IFingerprintService mFingerprintService;
@Mock
private ServiceProvider mProvider1;
@Mock
private ServiceProvider mProvider2;
@Captor
private ArgumentCaptor<Integer> mIdCaptor;
@Captor
private ArgumentCaptor<Integer> mStrengthCaptor;
private FingerprintSensorPropertiesInternal mProvider1Props;
private FingerprintSensorPropertiesInternal mProvider2Props;
private FingerprintServiceRegistry mRegistry;
@Before
public void setup() {
mProvider1Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_1,
STRENGTH_WEAK, 5 /* maxEnrollmentsPerUser */,
List.of(), FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
false /* resetLockoutRequiresHardwareAuthToken */);
mProvider2Props = new FingerprintSensorPropertiesInternal(SENSOR_ID_2,
STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
List.of(), FingerprintSensorProperties.TYPE_UNKNOWN,
false /* resetLockoutRequiresHardwareAuthToken */);
when(mProvider1.getSensorProperties()).thenReturn(List.of(mProvider1Props));
when(mProvider1.containsSensor(eq(SENSOR_ID_1))).thenReturn(true);
when(mProvider2.getSensorProperties()).thenReturn(List.of(mProvider2Props));
when(mProvider2.containsSensor(eq(SENSOR_ID_2))).thenReturn(true);
mRegistry = new FingerprintServiceRegistry(mFingerprintService, () -> mBiometricService);
}
@Test
public void registersAllProviders() throws Exception {
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
assertThat(mRegistry.getProviders()).containsExactly(mProvider1, mProvider2);
assertThat(mRegistry.getAllProperties()).containsExactly(mProvider1Props, mProvider2Props);
verify(mBiometricService, times(2)).registerAuthenticator(
mIdCaptor.capture(), eq(TYPE_FINGERPRINT), mStrengthCaptor.capture(), any());
assertThat(mIdCaptor.getAllValues()).containsExactly(SENSOR_ID_1, SENSOR_ID_2);
assertThat(mStrengthCaptor.getAllValues())
.containsExactly(BIOMETRIC_WEAK, BIOMETRIC_STRONG);
}
@Test
public void getsProviderById() {
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
assertThat(mRegistry.getProviderForSensor(SENSOR_ID_2)).isSameInstanceAs(mProvider2);
assertThat(mRegistry.getProviderForSensor(500)).isNull();
}
@Test
public void getsSingleProvider() {
mRegistry.registerAllInBackground(() -> List.of(mProvider1));
assertThat(mRegistry.getSingleProvider().second).isSameInstanceAs(mProvider1);
assertThat(mRegistry.getProviders()).containsExactly(mProvider1);
assertThat(mRegistry.getProviderForSensor(SENSOR_ID_1)).isSameInstanceAs(mProvider1);
}
@Test
public void registersListenerBeforeAllRegistered() {
final List<FingerprintSensorPropertiesInternal> all = new ArrayList<>();
mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
all.addAll(sensors);
}
});
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
}
@Test
public void registersListenerAfterAllRegistered() {
mRegistry.registerAllInBackground(() -> List.of(mProvider1, mProvider2));
final List<FingerprintSensorPropertiesInternal> all = new ArrayList<>();
mRegistry.addAllRegisteredCallback(new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
all.addAll(sensors);
}
});
assertThat(all).containsExactly(mProvider1Props, mProvider2Props);
}
}

View File

@@ -32,8 +32,7 @@ import android.hardware.biometrics.fingerprint.FingerprintSensorType;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorLocation;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.testing.TestableContext;
@@ -53,8 +52,6 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@Presubmit
@SmallTest
@@ -97,12 +94,9 @@ public class FingerprintServiceTest {
mContext.getTestablePermissions().setPermission(
USE_BIOMETRIC_INTERNAL, PackageManager.PERMISSION_GRANTED);
}
private void initServiceWith(String... aidlInstances) {
mService = new FingerprintService(mContext, mBiometricContext,
() -> mIBiometricService,
() -> aidlInstances,
(fqName) -> {
if (fqName.endsWith(NAME_DEFAULT)) return mIFingerprintDefault;
if (fqName.endsWith(NAME_VIRTUAL)) return mIFingerprintVirtual;
@@ -111,50 +105,29 @@ public class FingerprintServiceTest {
}
@Test
public void registerAuthenticators_defaultOnly() throws Exception {
initServiceWith(NAME_DEFAULT, NAME_VIRTUAL);
mService.mServiceWrapper.registerAuthenticators(List.of());
waitForRegistration();
public void registerAuthenticators_defaultOnly() throws RemoteException {
mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of());
verify(mIBiometricService).registerAuthenticator(eq(ID_DEFAULT), anyInt(), anyInt(), any());
}
@Test
public void registerAuthenticators_virtualOnly() throws Exception {
initServiceWith(NAME_DEFAULT, NAME_VIRTUAL);
public void registerAuthenticators_virtualOnly() throws RemoteException {
Settings.Secure.putInt(mSettingsRule.mockContentResolver(mContext),
Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED, 1);
mService.mServiceWrapper.registerAuthenticators(List.of());
waitForRegistration();
mService.registerAuthenticatorsForService(List.of(NAME_DEFAULT, NAME_VIRTUAL), List.of());
verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any());
}
@Test
public void registerAuthenticators_virtualAlwaysWhenNoOther() throws Exception {
initServiceWith(NAME_VIRTUAL);
mService.mServiceWrapper.registerAuthenticators(List.of());
waitForRegistration();
public void registerAuthenticators_virtualAlwaysWhenNoOther() throws RemoteException {
mService.registerAuthenticatorsForService(List.of(NAME_VIRTUAL), List.of());
verify(mIBiometricService).registerAuthenticator(eq(ID_VIRTUAL), anyInt(), anyInt(), any());
}
private void waitForRegistration() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mService.mServiceWrapper.addAuthenticatorsRegisteredCallback(
new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
latch.countDown();
}
});
latch.await(5, TimeUnit.SECONDS);
}
private static SensorProps createProps(int id, byte strength, byte type) {
final SensorProps props = new SensorProps();
props.commonProps = new CommonProps();