From e1b53af498e7d3b78f00f6cb59519c2b5e3bc0ea Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Tue, 20 Apr 2021 19:32:28 -0700 Subject: [PATCH 1/2] Consolidate registration of HIDL and AIDL HALs This CL establishes a single flow of registration for both HIDL and AIDL HALs. The registration of both is done on a separate thread to avoid blocking system server. Previously, only AIDL registration was done on a separate thread. Bug: 184677066 Test: atest CtsBiometricsTestCases Test: atest AuthServiceTest Test: atest Fingerprint21Test Test: atest Face10Test Change-Id: I4442db15a7b690bb34c6eb7e8793ab4411cbd6d2 --- .../biometrics/SensorPropertiesInternal.java | 2 +- .../android/hardware/face/IFaceService.aidl | 6 +- .../FingerprintSensorPropertiesInternal.java | 29 --- .../fingerprint/IFingerprintService.aidl | 6 +- .../android/hardware/iris/IIrisService.aidl | 8 +- .../server/biometrics/AuthService.java | 237 +++++++++++++----- .../sensors/BiometricServiceCallback.java | 28 --- .../sensors/face/FaceAuthenticator.java | 2 +- .../biometrics/sensors/face/FaceService.java | 126 +++++----- .../biometrics/sensors/face/hidl/Face10.java | 30 +-- .../fingerprint/FingerprintAuthenticator.java | 3 +- .../fingerprint/FingerprintService.java | 151 +++++------ .../fingerprint/hidl/Fingerprint21.java | 57 ++--- .../hidl/Fingerprint21UdfpsMock.java | 25 +- .../sensors/iris/IrisAuthenticator.java | 2 +- .../biometrics/sensors/iris/IrisService.java | 48 +++- .../java/com/android/server/SystemServer.java | 11 - .../server/biometrics/AuthServiceTest.java | 56 ++++- .../sensors/face/hidl/Face10Test.java | 21 +- .../fingerprint/hidl/Fingerprint21Test.java | 28 ++- 20 files changed, 504 insertions(+), 372 deletions(-) delete mode 100644 services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java index 17b2abf9f5d1e..f365ee6066d08 100644 --- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java +++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java @@ -44,7 +44,7 @@ public class SensorPropertiesInternal implements Parcelable { prop.resetLockoutRequiresHardwareAuthToken, prop.resetLockoutRequiresChallenge); } - protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength, + public SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength, int maxEnrollmentsPerUser, @NonNull List componentInfo, boolean resetLockoutRequiresHardwareAuthToken, boolean resetLockoutRequiresChallenge) { this.sensorId = sensorId; diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index 0b44150afa4df..270d662a02a0a 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -127,6 +127,8 @@ interface IFaceService { void getFeature(IBinder token, int userId, int feature, IFaceServiceReceiver receiver, String opPackageName); - // Give FaceService its ID. See AuthService.java - void initializeConfiguration(int sensorId, int strength); + // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because + // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist, + // hidlSensors must be non-null and empty. See AuthService.java + void registerAuthenticators(in List hidlSensors); } diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java index 58f6e62af3205..4ffe5f1896614 100644 --- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java +++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java @@ -20,7 +20,6 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFP import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC; import android.annotation.NonNull; -import android.content.Context; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.biometrics.SensorPropertiesInternal; @@ -92,34 +91,6 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna 1636 /* sensorLocationY */, 130 /* sensorRadius */); } - /** - * Initializes SensorProperties with specified values and values obtained from resources using - * context. - */ - // TODO(b/179175438): Remove this constructor once all HALs move to AIDL. - public FingerprintSensorPropertiesInternal(@NonNull Context context, int sensorId, - @SensorProperties.Strength int strength, int maxEnrollmentsPerUser, - @NonNull List componentInfo, - @FingerprintSensorProperties.SensorType int sensorType, - boolean resetLockoutRequiresHardwareAuthToken) { - super(sensorId, strength, maxEnrollmentsPerUser, componentInfo, - resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */); - this.sensorType = sensorType; - - int[] props = context.getResources().getIntArray( - com.android.internal.R.array.config_udfps_sensor_props); - if (props != null && props.length == 3) { - this.sensorLocationX = props[0]; - this.sensorLocationY = props[1]; - this.sensorRadius = props[2]; - } else { - // Fake coordinates that could be used for the fake UDFPS mode. - this.sensorLocationX = 540; - this.sensorLocationY = 1636; - this.sensorRadius = 130; - } - } - protected FingerprintSensorPropertiesInternal(Parcel in) { super(in); sensorType = in.readInt(); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 3bceacb5e479a..0e3cdd6b650a5 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -144,8 +144,10 @@ interface IFingerprintService { // Removes a callback set by addClientActiveCallback void removeClientActiveCallback(IFingerprintClientActiveCallback callback); - // Give FingerprintService its ID. See AuthService.java - void initializeConfiguration(int sensorId, int strength); + // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because + // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist, + // hidlSensors must be non-null and empty. See AuthService.java + void registerAuthenticators(in List hidlSensors); // Notifies about a finger touching the sensor area. void onPointerDown(int sensorId, int x, int y, float minor, float major); diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl index 3d26318343bef..98057d5482261 100644 --- a/core/java/android/hardware/iris/IIrisService.aidl +++ b/core/java/android/hardware/iris/IIrisService.aidl @@ -15,12 +15,16 @@ */ package android.hardware.iris; +import android.hardware.biometrics.SensorPropertiesInternal; + /** * Communication channel from client to the iris service. These methods are all require the * MANAGE_BIOMETRIC signature permission. * @hide */ interface IIrisService { - // Give IrisService its ID. See AuthService.java - void initializeConfiguration(int sensorId, int strength); + // Registers all HIDL and AIDL sensors. Only HIDL sensor properties need to be provided, because + // AIDL sensor properties are retrieved directly from the available HALs. If no HIDL HALs exist, + // hidlSensors must be non-null and empty. See AuthService.java + void registerAuthenticators(in List hidlSensors); } diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 88e47a0efd835..e34b183119814 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -30,12 +30,14 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import static android.hardware.biometrics.BiometricManager.Authenticators; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IAuthService; -import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; @@ -44,7 +46,11 @@ import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.SensorPropertiesInternal; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceService; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintService; import android.hardware.iris.IIrisService; import android.os.Binder; @@ -58,11 +64,10 @@ import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.server.SystemService; -import com.android.server.biometrics.sensors.face.FaceAuthenticator; -import com.android.server.biometrics.sensors.fingerprint.FingerprintAuthenticator; -import com.android.server.biometrics.sensors.iris.IrisAuthenticator; +import java.util.ArrayList; import java.util.List; /** @@ -574,81 +579,119 @@ public class AuthService extends SystemService { mImpl = new AuthServiceImpl(); } + + /** + * Registration of all HIDL and AIDL biometric HALs starts here. + * The flow looks like this: + * AuthService + * └── .onStart() + * └── .registerAuthenticators(...) + * ├── FaceService.registerAuthenticators(...) + * │ └── for (p : serviceProviders) + * │ └── for (s : p.sensors) + * │ └── BiometricService.registerAuthenticator(s) + * │ + * ├── FingerprintService.registerAuthenticators(...) + * │ └── for (p : serviceProviders) + * │ └── for (s : p.sensors) + * │ └── BiometricService.registerAuthenticator(s) + * │ + * └── IrisService.registerAuthenticators(...) + * └── for (p : serviceProviders) + * └── for (s : p.sensors) + * └── BiometricService.registerAuthenticator(s) + */ @Override public void onStart() { mBiometricService = mInjector.getBiometricService(); + final SensorConfig[] hidlConfigs; if (!mInjector.isHidlDisabled(getContext())) { - final String[] configs = mInjector.getConfiguration(getContext()); - for (String config : configs) { - try { - registerAuthenticator(new SensorConfig(config)); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - } + final String[] configStrings = mInjector.getConfiguration(getContext()); + hidlConfigs = new SensorConfig[configStrings.length]; + for (int i = 0; i < configStrings.length; ++i) { + hidlConfigs[i] = new SensorConfig(configStrings[i]); } + } else { + hidlConfigs = null; } + // Registers HIDL and AIDL authenticators, but only HIDL configs need to be provided. + registerAuthenticators(hidlConfigs); + mInjector.publishBinderService(this, mImpl); } - private void registerAuthenticator(SensorConfig config) throws RemoteException { - Slog.d(TAG, "Registering ID: " + config.id - + " Modality: " + config.modality - + " Strength: " + config.strength); + /** + * Registers HIDL and AIDL authenticators for all of the available modalities. + * + * @param hidlSensors Array of {@link SensorConfig} configuration for all of the HIDL sensors + * available on the device. This array may contain configuration for + * different modalities and different sensors of the same modality in + * arbitrary order. Can be null if no HIDL sensors exist on the device. + */ + private void registerAuthenticators(@Nullable SensorConfig[] hidlSensors) { + List hidlFingerprintSensors = new ArrayList<>(); + List hidlFaceSensors = new ArrayList<>(); + // Iris doesn't have IrisSensorPropertiesInternal, using SensorPropertiesInternal instead. + List hidlIrisSensors = new ArrayList<>(); - final IBiometricAuthenticator.Stub authenticator; + if (hidlSensors != null) { + for (SensorConfig sensor : hidlSensors) { + Slog.d(TAG, "Registering HIDL ID: " + sensor.id + " Modality: " + sensor.modality + + " Strength: " + sensor.strength); + switch (sensor.modality) { + case TYPE_FINGERPRINT: + hidlFingerprintSensors.add( + getHidlFingerprintSensorProps(sensor.id, sensor.strength)); + break; - switch (config.modality) { - case TYPE_FINGERPRINT: - final IFingerprintService fingerprintService = mInjector.getFingerprintService(); - if (fingerprintService == null) { - Slog.e(TAG, "Attempting to register with null FingerprintService." - + " Please check your device configuration."); - return; + case TYPE_FACE: + hidlFaceSensors.add(getHidlFaceSensorProps(sensor.id, sensor.strength)); + break; + + case TYPE_IRIS: + hidlIrisSensors.add(getHidlIrisSensorProps(sensor.id, sensor.strength)); + break; + + default: + Slog.e(TAG, "Unknown modality: " + sensor.modality); } - - // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require - // initialization from here. AIDL HALs are initialized by FingerprintService since - // the HAL interface provides ID, strength, and other configuration information. - fingerprintService.initializeConfiguration(config.id, config.strength); - authenticator = new FingerprintAuthenticator(fingerprintService, config.id); - break; - - case TYPE_FACE: - final IFaceService faceService = mInjector.getFaceService(); - if (faceService == null) { - Slog.e(TAG, "Attempting to register with null FaceService. Please check " - + " your device configuration."); - return; - } - - // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require - // initialization from here. AIDL HALs are initialized by FaceService since - // the HAL interface provides ID, strength, and other configuration information. - faceService.initializeConfiguration(config.id, config.strength); - authenticator = new FaceAuthenticator(faceService, config.id); - break; - - case TYPE_IRIS: - final IIrisService irisService = mInjector.getIrisService(); - if (irisService == null) { - Slog.e(TAG, "Attempting to register with null IrisService. Please check" - + " your device configuration."); - return; - } - - irisService.initializeConfiguration(config.id, config.strength); - authenticator = new IrisAuthenticator(irisService, config.id); - break; - - default: - Slog.e(TAG, "Unknown modality: " + config.modality); - return; + } } - mBiometricService.registerAuthenticator(config.id, config.modality, config.strength, - authenticator); + final IFingerprintService fingerprintService = mInjector.getFingerprintService(); + if (fingerprintService != null) { + try { + fingerprintService.registerAuthenticators(hidlFingerprintSensors); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when registering fingerprint authenticators", e); + } + } else if (hidlFingerprintSensors.size() > 0) { + Slog.e(TAG, "HIDL fingerprint configuration exists, but FingerprintService is null."); + } + + final IFaceService faceService = mInjector.getFaceService(); + if (faceService != null) { + try { + faceService.registerAuthenticators(hidlFaceSensors); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when registering face authenticators", e); + } + } else if (hidlFaceSensors.size() > 0) { + Slog.e(TAG, "HIDL face configuration exists, but FaceService is null."); + } + + final IIrisService irisService = mInjector.getIrisService(); + if (irisService != null) { + try { + irisService.registerAuthenticators(hidlIrisSensors); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when registering iris authenticators", e); + } + } else if (hidlIrisSensors.size() > 0) { + Slog.e(TAG, "HIDL iris configuration exists, but IrisService is null."); + } } private void checkInternalPermission() { @@ -674,4 +717,72 @@ public class AuthService extends SystemService { return modality == BiometricAuthenticator.TYPE_CREDENTIAL ? modality : (modality & ~BiometricAuthenticator.TYPE_CREDENTIAL); } + + + private FingerprintSensorPropertiesInternal getHidlFingerprintSensorProps(int sensorId, + @BiometricManager.Authenticators.Types int strength) { + // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS. + final int[] udfpsProps = getContext().getResources().getIntArray( + com.android.internal.R.array.config_udfps_sensor_props); + + final boolean isUdfps = !ArrayUtils.isEmpty(udfpsProps); + + // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor. + final boolean isPowerbuttonFps = getContext().getResources().getBoolean( + R.bool.config_is_powerbutton_fps); + + final @FingerprintSensorProperties.SensorType int sensorType; + if (isUdfps) { + sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; + } else if (isPowerbuttonFps) { + sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON; + } else { + sensorType = FingerprintSensorProperties.TYPE_REAR; + } + + // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT + // cannot be checked. + final boolean resetLockoutRequiresHardwareAuthToken = false; + final int maxEnrollmentsPerUser = getContext().getResources().getInteger( + R.integer.config_fingerprintMaxTemplatesPerUser); + + final List componentInfo = new ArrayList<>(); + if (isUdfps && udfpsProps.length == 3) { + return new FingerprintSensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, + componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken, udfpsProps[0], + udfpsProps[1], udfpsProps[2]); + } else { + return new FingerprintSensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, + componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken); + } + } + + private FaceSensorPropertiesInternal getHidlFaceSensorProps(int sensorId, + @BiometricManager.Authenticators.Types int strength) { + final boolean supportsSelfIllumination = getContext().getResources().getBoolean( + R.bool.config_faceAuthSupportsSelfIllumination); + final int maxTemplatesAllowed = getContext().getResources().getInteger( + R.integer.config_faceMaxTemplatesPerUser); + final List componentInfo = new ArrayList<>(); + final boolean supportsFaceDetect = false; + final boolean resetLockoutRequiresChallenge = true; + return new FaceSensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed, + componentInfo, FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetect, + supportsSelfIllumination, resetLockoutRequiresChallenge); + } + + private SensorPropertiesInternal getHidlIrisSensorProps(int sensorId, + @BiometricManager.Authenticators.Types int strength) { + final int maxEnrollmentsPerUser = 1; + final List componentInfo = new ArrayList<>(); + final boolean resetLockoutRequiresHardwareAuthToken = false; + final boolean resetLockoutRequiresChallenge = false; + return new SensorPropertiesInternal(sensorId, + Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, + componentInfo, resetLockoutRequiresHardwareAuthToken, + resetLockoutRequiresChallenge); + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java deleted file mode 100644 index 2ae6ccd73e3da..0000000000000 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2020 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; - -/** - * System_server services that require BiometricService to load before finishing initialization - * should implement this interface. - */ -public interface BiometricServiceCallback { - /** - * Notifies the service that BiometricService is initialized. - */ - void onBiometricServiceReady(); -} diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java index 0002ad249376d..0bc4f1b54d592 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java @@ -36,7 +36,7 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub { private final IFaceService mFaceService; private final int mSensorId; - public FaceAuthenticator(IFaceService faceService, int sensorId) throws RemoteException { + public FaceAuthenticator(IFaceService faceService, int sensorId) { mFaceService = faceService; mSensorId = sensorId; } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java index ada84769b9ef2..94d47aa029a26 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java @@ -57,7 +57,6 @@ 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.sensors.BiometricServiceCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -76,7 +75,7 @@ import java.util.List; * The service is responsible for maintaining a list of clients and dispatching all * face-related events. */ -public class FaceService extends SystemService implements BiometricServiceCallback { +public class FaceService extends SystemService { protected static final String TAG = "FaceService"; @@ -618,12 +617,76 @@ public class FaceService extends SystemService implements BiometricServiceCallba new ClientMonitorCallbackConverter(receiver), opPackageName); } + private void addHidlProviders(@NonNull List hidlSensors) { + for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) { + mServiceProviders.add( + new Face10(getContext(), hidlSensor, mLockoutResetDispatcher)); + } + } + + private void addAidlProviders() { + final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR); + if (instances == null || instances.length == 0) { + return; + } + for (String instance : instances) { + final String fqName = IFace.DESCRIPTOR + "/" + instance; + final IFace face = IFace.Stub.asInterface( + ServiceManager.waitForDeclaredService(fqName)); + if (face == null) { + Slog.e(TAG, "Unable to get declared service: " + fqName); + continue; + } + try { + final SensorProps[] props = face.getSensorProps(); + final FaceProvider provider = new FaceProvider(getContext(), props, instance, + mLockoutResetDispatcher); + mServiceProviders.add(provider); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); + } + } + } + @Override // Binder call - public void initializeConfiguration(int sensorId, - @BiometricManager.Authenticators.Types int strength) { + public void registerAuthenticators( + @NonNull List hidlSensors) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mServiceProviders.add( - new Face10(getContext(), sensorId, strength, 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 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); + } + } + } + }); } } @@ -635,57 +698,6 @@ public class FaceService extends SystemService implements BiometricServiceCallba mServiceProviders = new ArrayList<>(); } - @Override - public void onBiometricServiceReady() { - final IBiometricService biometricService = IBiometricService.Stub.asInterface( - ServiceManager.getService(Context.BIOMETRIC_SERVICE)); - - final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR); - if (instances == null || instances.length == 0) { - return; - } - - // If for some reason the HAL is not started before the system service, do not block - // the rest of system server. 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(() -> { - for (String instance : instances) { - final String fqName = IFace.DESCRIPTOR + "/" + instance; - final IFace face = IFace.Stub.asInterface( - ServiceManager.waitForDeclaredService(fqName)); - try { - final SensorProps[] props = face.getSensorProps(); - final FaceProvider provider = new FaceProvider(getContext(), props, instance, - mLockoutResetDispatcher); - mServiceProviders.add(provider); - - // Register each sensor individually with BiometricService - for (SensorProps prop : props) { - final int sensorId = prop.commonProps.sensorId; - @BiometricManager.Authenticators.Types int strength = - Utils.propertyStrengthToAuthenticatorStrength( - prop.commonProps.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); - } - } - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when initializing instance: " + fqName); - } - } - }); - } - @Override public void onStart() { publishBinderService(Context.FACE_SERVICE, mServiceWrapper); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java index a40155b2df7d6..5dfc5907060f5 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java @@ -25,15 +25,12 @@ import android.content.Context; import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricFaceConstants; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback; import android.hardware.face.Face; -import android.hardware.face.FaceSensorProperties; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceServiceReceiver; import android.os.Binder; @@ -51,7 +48,6 @@ import android.provider.Settings; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.SensorServiceStateProto; @@ -66,7 +62,6 @@ import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.EnumerateConsumer; import com.android.server.biometrics.sensors.ErrorConsumer; import com.android.server.biometrics.sensors.HalClientMonitor; -import com.android.server.biometrics.sensors.Interruptable; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; import com.android.server.biometrics.sensors.PerformanceTracker; @@ -327,19 +322,13 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } } - @VisibleForTesting - Face10(@NonNull Context context, int sensorId, - @BiometricManager.Authenticators.Types int strength, + @VisibleForTesting Face10(@NonNull Context context, + @NonNull FaceSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, - boolean supportsSelfIllumination, int maxTemplatesAllowed, @NonNull BiometricScheduler scheduler) { - mSensorProperties = new FaceSensorPropertiesInternal(sensorId, - Utils.authenticatorStrengthToPropertyStrength(strength), - maxTemplatesAllowed, new ArrayList() /* componentInfo */, - FaceSensorProperties.TYPE_UNKNOWN, false /* supportsFaceDetect */, - supportsSelfIllumination, true /* resetLockoutRequiresChallenge */); + mSensorProperties = sensorProps; mContext = context; - mSensorId = sensorId; + mSensorId = sensorProps.sensorId; mScheduler = scheduler; mHandler = new Handler(Looper.getMainLooper()); mUsageStats = new UsageStats(context); @@ -347,8 +336,8 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { mLazyDaemon = Face10.this::getDaemon; mLockoutTracker = new LockoutHalImpl(); mLockoutResetDispatcher = lockoutResetDispatcher; - mHalResultController = new HalResultController(sensorId, context, mHandler, mScheduler, - mLockoutTracker, lockoutResetDispatcher); + mHalResultController = new HalResultController(sensorProps.sensorId, context, mHandler, + mScheduler, mLockoutTracker, lockoutResetDispatcher); mHalResultController.setCallback(() -> { mDaemon = null; mCurrentUserId = UserHandle.USER_NULL; @@ -361,12 +350,9 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { } } - public Face10(@NonNull Context context, int sensorId, - @BiometricManager.Authenticators.Types int strength, + public Face10(@NonNull Context context, @NonNull FaceSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher) { - this(context, sensorId, strength, lockoutResetDispatcher, - context.getResources().getBoolean(R.bool.config_faceAuthSupportsSelfIllumination), - context.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser), + this(context, sensorProps, lockoutResetDispatcher, new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */)); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java index 81096802a78b6..1e5942930b018 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java @@ -36,8 +36,7 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub private final IFingerprintService mFingerprintService; private final int mSensorId; - public FingerprintAuthenticator(IFingerprintService fingerprintService, int sensorId) - throws RemoteException { + public FingerprintAuthenticator(IFingerprintService fingerprintService, int sensorId) { mFingerprintService = fingerprintService; mSensorId = sensorId; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index b780222da380c..2b0637fe335a0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -76,7 +76,6 @@ 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.sensors.BiometricServiceCallback; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -96,7 +95,7 @@ import java.util.concurrent.Executor; * The service is responsible for maintaining a list of clients and dispatching all * fingerprint-related events. */ -public class FingerprintService extends SystemService implements BiometricServiceCallback { +public class FingerprintService extends SystemService { protected static final String TAG = "FingerprintService"; @@ -775,24 +774,89 @@ public class FingerprintService extends SystemService implements BiometricServic mGestureAvailabilityDispatcher.removeCallback(callback); } + private void addHidlProviders(List hidlSensors) { + for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) { + final Fingerprint21 fingerprint21; + if ((Build.IS_USERDEBUG || Build.IS_ENG) + && getContext().getResources().getBoolean(R.bool.allow_test_udfps) + && Settings.Secure.getIntForUser(getContext().getContentResolver(), + Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */, + UserHandle.USER_CURRENT) != 0) { + fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), hidlSensor, + mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + } else { + fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor, + mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + } + mServiceProviders.add(fingerprint21); + } + } + + private void addAidlProviders() { + final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR); + if (instances == null || instances.length == 0) { + return; + } + for (String instance : instances) { + final String fqName = IFingerprint.DESCRIPTOR + "/" + instance; + final IFingerprint fp = IFingerprint.Stub.asInterface( + ServiceManager.waitForDeclaredService(fqName)); + if (fp == null) { + Slog.e(TAG, "Unable to get declared service: " + fqName); + continue; + } + try { + final SensorProps[] props = fp.getSensorProps(); + final FingerprintProvider provider = + new FingerprintProvider(getContext(), props, instance, + mLockoutResetDispatcher, mGestureAvailabilityDispatcher); + mServiceProviders.add(provider); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception in getSensorProps: " + fqName); + } + } + } + @Override // Binder call - public void initializeConfiguration(int sensorId, - @BiometricManager.Authenticators.Types int strength) { + public void registerAuthenticators( + @NonNull List hidlSensors) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - final Fingerprint21 fingerprint21; - if ((Build.IS_USERDEBUG || Build.IS_ENG) - && getContext().getResources().getBoolean(R.bool.allow_test_udfps) - && Settings.Secure.getIntForUser(getContext().getContentResolver(), - Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */, - UserHandle.USER_CURRENT) != 0) { - fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId, - strength, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); - } else { - fingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength, - mLockoutResetDispatcher, mGestureAvailabilityDispatcher); - } - mServiceProviders.add(fingerprint21); + // 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 props = + provider.getSensorProperties(); + for (FingerprintSensorPropertiesInternal prop : props) { + final int sensorId = prop.sensorId; + final @BiometricManager.Authenticators.Types 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); + } + } + } + }); } @Override @@ -806,7 +870,6 @@ public class FingerprintService extends SystemService implements BiometricServic } provider.onPointerDown(sensorId, x, y, minor, major); } - @Override public void onPointerUp(int sensorId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); @@ -845,58 +908,6 @@ public class FingerprintService extends SystemService implements BiometricServic mFingerprintStateCallback = new FingerprintStateCallback(); } - @Override - public void onBiometricServiceReady() { - final IBiometricService biometricService = IBiometricService.Stub.asInterface( - ServiceManager.getService(Context.BIOMETRIC_SERVICE)); - - final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR); - if (instances == null || instances.length == 0) { - return; - } - - // If for some reason the HAL is not started before the system service, do not block - // the rest of system server. 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(() -> { - for (String instance : instances) { - final String fqName = IFingerprint.DESCRIPTOR + "/" + instance; - final IFingerprint fp = IFingerprint.Stub.asInterface( - ServiceManager.waitForDeclaredService(fqName)); - try { - final SensorProps[] props = fp.getSensorProps(); - final FingerprintProvider provider = - new FingerprintProvider(getContext(), props, instance, - mLockoutResetDispatcher, mGestureAvailabilityDispatcher); - mServiceProviders.add(provider); - - // Register each sensor individually with BiometricService - for (SensorProps prop : props) { - final int sensorId = prop.commonProps.sensorId; - @BiometricManager.Authenticators.Types int strength = - Utils.propertyStrengthToAuthenticatorStrength( - prop.commonProps.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); - } - } - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when initializing instance: " + fqName); - } - } - }); - } - @Override public void onStart() { publishBinderService(Context.FINGERPRINT_SERVICE, mServiceWrapper); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index ebfd5347241d5..3528690e64599 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -26,9 +26,7 @@ import android.app.UserSwitchObserver; import android.content.Context; import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricConstants; -import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; @@ -50,9 +48,7 @@ import android.os.UserManager; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.SensorServiceStateProto; import com.android.server.biometrics.SensorStateProto; @@ -314,17 +310,22 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } } - Fingerprint21(@NonNull Context context, @NonNull BiometricScheduler scheduler, - @NonNull Handler handler, int sensorId, - @BiometricManager.Authenticators.Types int strength, + Fingerprint21(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, + @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller) { mContext = context; - mSensorId = sensorId; + + mSensorProperties = sensorProps; + mSensorId = sensorProps.sensorId; + mIsUdfps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL + || sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC; + mIsPowerbuttonFps = sensorProps.sensorType == FingerprintSensorProperties.TYPE_POWER_BUTTON; + mScheduler = scheduler; mHandler = handler; mActivityTaskManager = ActivityTaskManager.getInstance(); - mTaskStackListener = new BiometricTaskStackListener(); mAuthenticatorIds = Collections.synchronizedMap(new HashMap<>()); mLazyDaemon = Fingerprint21.this::getDaemon; @@ -341,46 +342,20 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } catch (RemoteException e) { Slog.e(TAG, "Unable to register user switch observer"); } - - // TODO(b/179175438): Remove this code block after transition to AIDL. - // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS. - mIsUdfps = !ArrayUtils.isEmpty( - mContext.getResources().getIntArray(R.array.config_udfps_sensor_props)); - - // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor. - mIsPowerbuttonFps = mContext.getResources().getBoolean(R.bool.config_is_powerbutton_fps); - - final @FingerprintSensorProperties.SensorType int sensorType; - if (mIsUdfps) { - sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; - } else if (mIsPowerbuttonFps) { - sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON; - } else { - sensorType = FingerprintSensorProperties.TYPE_REAR; - } - - // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT - // cannot be checked - final boolean resetLockoutRequiresHardwareAuthToken = false; - final int maxEnrollmentsPerUser = mContext.getResources() - .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser); - - mSensorProperties = new FingerprintSensorPropertiesInternal(context, sensorId, - Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser, - new ArrayList() /* componentInfo */, sensorType, - resetLockoutRequiresHardwareAuthToken); } - public static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength, + public static Fingerprint21 newInstance(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { final Handler handler = new Handler(Looper.getMainLooper()); final BiometricScheduler scheduler = new BiometricScheduler(TAG, gestureAvailabilityDispatcher); - final HalResultController controller = new HalResultController(sensorId, context, handler, + final HalResultController controller = new HalResultController(sensorProps.sensorId, + context, handler, scheduler); - return new Fingerprint21(context, scheduler, handler, sensorId, strength, - lockoutResetDispatcher, controller); + return new Fingerprint21(context, sensorProps, scheduler, handler, lockoutResetDispatcher, + controller); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java index 48419c35e28ec..d1020a6ff068c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java @@ -21,8 +21,6 @@ import android.annotation.Nullable; import android.app.trust.TrustManager; import android.content.ContentResolver; import android.content.Context; -import android.hardware.biometrics.BiometricManager; -import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; @@ -39,7 +37,6 @@ import android.util.Slog; import android.util.SparseBooleanArray; import com.android.internal.R; -import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.AuthenticationConsumer; import com.android.server.biometrics.sensors.BaseClientMonitor; import com.android.server.biometrics.sensors.BiometricScheduler; @@ -271,8 +268,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } } - public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, int sensorId, - @BiometricManager.Authenticators.Types int strength, + public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { Slog.d(TAG, "Creating Fingerprint23Mock!"); @@ -281,8 +278,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage final TestableBiometricScheduler scheduler = new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher); final MockHalResultController controller = - new MockHalResultController(sensorId, context, handler, scheduler); - return new Fingerprint21UdfpsMock(context, scheduler, handler, sensorId, strength, + new MockHalResultController(sensorProps.sensorId, context, handler, scheduler); + return new Fingerprint21UdfpsMock(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); } @@ -407,12 +404,12 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } private Fingerprint21UdfpsMock(@NonNull Context context, + @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull TestableBiometricScheduler scheduler, - @NonNull Handler handler, int sensorId, - @BiometricManager.Authenticators.Types int strength, + @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull MockHalResultController controller) { - super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher, controller); + super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); mScheduler = scheduler; mScheduler.init(this); mHandler = handler; @@ -420,11 +417,11 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage final boolean resetLockoutRequiresHardwareAuthToken = false; final int maxTemplatesAllowed = mContext.getResources() .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser); - mSensorProperties = new FingerprintSensorPropertiesInternal(sensorId, - Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed, - new ArrayList() /* componentInfo */, + mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId, + sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, - resetLockoutRequiresHardwareAuthToken); + resetLockoutRequiresHardwareAuthToken, sensorProps.sensorLocationX, + sensorProps.sensorLocationY, sensorProps.sensorRadius); mMockHalResultController = controller; mUserHasTrust = new SparseBooleanArray(); mTrustManager = context.getSystemService(TrustManager.class); diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java index 1003c26f966e8..491818520e3cc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java @@ -35,7 +35,7 @@ import com.android.server.biometrics.sensors.LockoutTracker; public final class IrisAuthenticator extends IBiometricAuthenticator.Stub { private final IIrisService mIrisService; - public IrisAuthenticator(IIrisService irisService, int sensorId) throws RemoteException { + public IrisAuthenticator(IIrisService irisService, int sensorId) { mIrisService = irisService; } diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java index 08b24897581fd..d684bb8439674 100644 --- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java +++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java @@ -17,14 +17,26 @@ package com.android.server.biometrics.sensors.iris; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; +import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import android.annotation.NonNull; import android.content.Context; +import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.IBiometricService; +import android.hardware.biometrics.SensorPropertiesInternal; import android.hardware.iris.IIrisService; +import android.os.Handler; +import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; +import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.biometrics.Utils; +import java.util.List; + /** * A service to manage multiple clients that want to access the Iris HAL API. * The service is responsible for maintaining a list of clients and dispatching all @@ -37,22 +49,54 @@ public class IrisService extends SystemService { private static final String TAG = "IrisService"; + private final IrisServiceWrapper mServiceWrapper; + /** * Receives the incoming binder calls from IrisManager. */ private final class IrisServiceWrapper extends IIrisService.Stub { @Override // Binder call - public void initializeConfiguration(int sensorId, int strength) { + public void registerAuthenticators(@NonNull List hidlSensors) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + // 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(() -> { + final IBiometricService biometricService = IBiometricService.Stub.asInterface( + ServiceManager.getService(Context.BIOMETRIC_SERVICE)); + + for (SensorPropertiesInternal hidlSensor : hidlSensors) { + final int sensorId = hidlSensor.sensorId; + final @BiometricManager.Authenticators.Types int strength = + Utils.propertyStrengthToAuthenticatorStrength( + hidlSensor.sensorStrength); + final IrisAuthenticator authenticator = new IrisAuthenticator(mServiceWrapper, + sensorId); + try { + biometricService.registerAuthenticator(sensorId, TYPE_IRIS, strength, + authenticator); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when registering sensorId: " + sensorId); + } + } + }); } } public IrisService(@NonNull Context context) { super(context); + mServiceWrapper = new IrisServiceWrapper(); } @Override public void onStart() { - publishBinderService(Context.IRIS_SERVICE, new IrisServiceWrapper()); + publishBinderService(Context.IRIS_SERVICE, mServiceWrapper); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 6dedca190e2b9..8dc501119af13 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -108,7 +108,6 @@ import com.android.server.attention.AttentionManagerService; import com.android.server.audio.AudioService; import com.android.server.biometrics.AuthService; import com.android.server.biometrics.BiometricService; -import com.android.server.biometrics.sensors.BiometricServiceCallback; import com.android.server.biometrics.sensors.face.FaceService; import com.android.server.biometrics.sensors.fingerprint.FingerprintService; import com.android.server.biometrics.sensors.iris.IrisService; @@ -214,11 +213,9 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; -import java.util.List; import java.util.Locale; import java.util.Timer; import java.util.TreeSet; @@ -2334,12 +2331,10 @@ public final class SystemServer implements Dumpable { final boolean hasFeatureFingerprint = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT); - final List biometricServiceCallback = new ArrayList<>(); if (hasFeatureFace) { t.traceBegin("StartFaceSensor"); final FaceService faceService = mSystemServiceManager.startService(FaceService.class); - biometricServiceCallback.add(faceService); t.traceEnd(); } @@ -2353,18 +2348,12 @@ public final class SystemServer implements Dumpable { t.traceBegin("StartFingerprintSensor"); final FingerprintService fingerprintService = mSystemServiceManager.startService(FingerprintService.class); - biometricServiceCallback.add(fingerprintService); t.traceEnd(); } // Start this service after all biometric sensor services are started. t.traceBegin("StartBiometricService"); mSystemServiceManager.startService(BiometricService.class); - for (BiometricServiceCallback service : biometricServiceCallback) { - Slog.d(TAG, "Notifying onBiometricServiceReady for: " - + service.getClass().getSimpleName()); - service.onBiometricServiceReady(); - } t.traceEnd(); t.traceBegin("StartAuthService"); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java index 10a7a50003174..6f0c8e1004c4d 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java @@ -31,11 +31,14 @@ import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.PromptInfo; +import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceService; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintService; import android.hardware.iris.IIrisService; import android.os.Binder; @@ -45,11 +48,17 @@ import android.platform.test.annotations.Presubmit; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; +import com.android.internal.R; + import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; + @Presubmit @SmallTest public class AuthServiceTest { @@ -62,6 +71,8 @@ public class AuthServiceTest { @Mock private Context mContext; @Mock + private Resources mResources; + @Mock private PackageManager mPackageManager; @Mock IBiometricServiceReceiver mReceiver; @@ -77,6 +88,10 @@ public class AuthServiceTest { IFaceService mFaceService; @Mock AppOpsManager mAppOpsManager; + @Captor + private ArgumentCaptor> mFingerprintPropsCaptor; + @Captor + private ArgumentCaptor> mFacePropsCaptor; @Before public void setUp() { @@ -89,7 +104,16 @@ public class AuthServiceTest { "2:8:15", // ID2:Face:Strong }; + when(mResources.getIntArray(eq(R.array.config_udfps_sensor_props))).thenReturn(new int[0]); + when(mResources.getBoolean(eq(R.bool.config_is_powerbutton_fps))).thenReturn(false); + when(mResources.getInteger(eq(R.integer.config_fingerprintMaxTemplatesPerUser))).thenReturn( + 1); + when(mResources.getBoolean(eq(R.bool.config_faceAuthSupportsSelfIllumination))).thenReturn( + false); + when(mResources.getInteger(eq(R.integer.config_faceMaxTemplatesPerUser))).thenReturn(1); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getResources()).thenReturn(mResources); when(mInjector.getBiometricService()).thenReturn(mBiometricService); when(mInjector.getConfiguration(any())).thenReturn(config); when(mInjector.getFingerprintService()).thenReturn(mFingerprintService); @@ -119,11 +143,18 @@ public class AuthServiceTest { } @Test - public void testRegisterAuthenticator_initializesConfiguration() throws Exception { + public void testRegisterAuthenticator_registerAuthenticators() throws Exception { + final int fingerprintId = 0; + final int fingerprintStrength = 15; + + final int faceId = 1; + final int faceStrength = 4095; final String[] config = { - "0:2:15", // ID0:Fingerprint:Strong - "1:8:4095", // ID2:Face:Convenience + // ID0:Fingerprint:Strong + String.format("%d:2:%d", fingerprintId, fingerprintStrength), + // ID2:Face:Convenience + String.format("%d:8:%d", faceId, faceStrength) }; when(mInjector.getConfiguration(any())).thenReturn(config); @@ -131,15 +162,18 @@ public class AuthServiceTest { mAuthService = new AuthService(mContext, mInjector); mAuthService.onStart(); - final int fingerprintId = 0; - final int faceId = 1; + verify(mFingerprintService).registerAuthenticators(mFingerprintPropsCaptor.capture()); + final FingerprintSensorPropertiesInternal fingerprintProp = + mFingerprintPropsCaptor.getValue().get(0); + assertEquals(fingerprintProp.sensorId, fingerprintId); + assertEquals(fingerprintProp.sensorStrength, + Utils.authenticatorStrengthToPropertyStrength(fingerprintStrength)); - final int fingerprintStrength = 15; - final int faceStrength = 4095; - - verify(mFingerprintService).initializeConfiguration(eq(fingerprintId), - eq(fingerprintStrength)); - verify(mFaceService).initializeConfiguration(eq(faceId), eq(faceStrength)); + verify(mFaceService).registerAuthenticators(mFacePropsCaptor.capture()); + final FaceSensorPropertiesInternal faceProp = mFacePropsCaptor.getValue().get(0); + assertEquals(faceProp.sensorId, faceId); + assertEquals(faceProp.sensorStrength, + Utils.authenticatorStrengthToPropertyStrength(faceStrength)); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java index 392535e8eea1a..0b59be65b8879 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java @@ -22,7 +22,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.ComponentInfoInternal; +import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; import android.os.Binder; import android.os.IBinder; import android.os.UserManager; @@ -40,6 +43,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.List; @Presubmit @SmallTest @@ -71,9 +75,18 @@ public class Face10Test { when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>()); mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); - mFace10 = new Face10(mContext, SENSOR_ID, BiometricManager.Authenticators.BIOMETRIC_STRONG, - mLockoutResetDispatcher, false /* supportsSelfIllumination */, - 1 /* maxTemplatesAllowed */, mScheduler); + + final int maxEnrollmentsPerUser = 1; + final List componentInfo = new ArrayList<>(); + final boolean supportsFaceDetection = false; + final boolean supportsSelfIllumination = false; + final boolean resetLockoutRequiresChallenge = false; + final FaceSensorPropertiesInternal sensorProps = new FaceSensorPropertiesInternal(SENSOR_ID, + SensorProperties.STRENGTH_STRONG, maxEnrollmentsPerUser, componentInfo, + FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetection, supportsSelfIllumination, + resetLockoutRequiresChallenge); + + mFace10 = new Face10(mContext, sensorProps, mLockoutResetDispatcher, mScheduler); mBinder = new Binder(); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java index 904ade82a51f9..0a0dcc97272b9 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java @@ -25,8 +25,10 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; -import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Handler; import android.os.Looper; import android.os.UserManager; @@ -46,6 +48,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.List; @Presubmit @SmallTest @@ -83,10 +86,18 @@ public class Fingerprint21Test { .thenReturn(5); mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); - mFingerprint21 = new TestableFingerprint21(mContext, mScheduler, - new Handler(Looper.getMainLooper()), SENSOR_ID, - BiometricManager.Authenticators.BIOMETRIC_WEAK, mLockoutResetDispatcher, - mHalResultController); + + final int maxEnrollmentsPerUser = 1; + final List componentInfo = new ArrayList<>(); + final boolean resetLockoutRequiresHardwareAuthToken = false; + final FingerprintSensorPropertiesInternal sensorProps = + new FingerprintSensorPropertiesInternal(SENSOR_ID, + FingerprintSensorProperties.STRENGTH_WEAK, maxEnrollmentsPerUser, + componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN, + resetLockoutRequiresHardwareAuthToken); + + mFingerprint21 = new TestableFingerprint21(mContext, sensorProps, mScheduler, + new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController); } @Test @@ -107,12 +118,11 @@ public class Fingerprint21Test { private static class TestableFingerprint21 extends Fingerprint21 { TestableFingerprint21(@NonNull Context context, - @NonNull BiometricScheduler scheduler, - @NonNull Handler handler, int sensorId, int strength, + @NonNull FingerprintSensorPropertiesInternal sensorProps, + @NonNull BiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull HalResultController controller) { - super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher, - controller); + super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller); } @Override From 06f04c041cf65b19cbf736852996760b1284124c Mon Sep 17 00:00:00 2001 From: Ilya Matyukhin Date: Thu, 15 Apr 2021 19:23:47 -0700 Subject: [PATCH 2/2] Notify AuthController when fingerprint providers are ready This change introduces a callback that AuthController can provide to FingerprintService to get notified when all of the fingerprint providers are available. This fixes the bug where UDFPS overlay is not available if SystemUI starts before the fingerprint HAL, because SystemUI would query the fingerprint providers on startup. Bug: 184677066 Test: atest AuthControllerTest Test: on device Change-Id: I165d67bdda09ea10dd5aac539c4155e6b158227d --- .../fingerprint/FingerprintManager.java | 25 ++++++ ...printAuthenticatorsRegisteredCallback.aidl | 35 ++++++++ .../fingerprint/IFingerprintService.aidl | 5 ++ .../systemui/biometrics/AuthController.java | 58 ++++++++----- .../biometrics/AuthControllerTest.java | 11 ++- .../fingerprint/FingerprintService.java | 87 +++++++++++++++++-- 6 files changed, 190 insertions(+), 31 deletions(-) create mode 100644 core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 88d5ba8be8aba..cc1aeeb92685a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -1012,6 +1012,31 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing return sensorProps.sensorType == TYPE_POWER_BUTTON; } + /** + * Adds a callback that gets called when the service registers all of the fingerprint + * authenticators (HALs). + * + * If the fingerprint 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( + IFingerprintAuthenticatorsRegisteredCallback callback) { + if (mService != null) { + try { + mService.addAuthenticatorsRegisteredCallback(callback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + Slog.w(TAG, "addProvidersAvailableCallback(): Service not connected!"); + } + } + /** * @hide */ diff --git a/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl new file mode 100644 index 0000000000000..5a2c9311eaf92 --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintAuthenticatorsRegisteredCallback.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 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.fingerprint; + +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import java.util.List; + +/** + * Callback to notify FingerprintManager that FingerprintService has registered all of the + * fingerprint authenticators (HALs). + * See {@link android.hardware.fingerprint.IFingerprintService#registerAuthenticators}. + * + * @hide + */ +oneway interface IFingerprintAuthenticatorsRegisteredCallback { + /** + * Notifies FingerprintManager that all of the fingerprint authenticators have been registered. + * + * @param sensors A consolidated list of sensor properties for all of the authenticators. + */ + void onAllAuthenticatorsRegistered(in List sensors); +} diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 0e3cdd6b650a5..833747f19a0c0 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -21,6 +21,7 @@ import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.fingerprint.IFingerprintClientActiveCallback; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.IFingerprintStateListener; import android.hardware.fingerprint.IUdfpsOverlayController; @@ -149,6 +150,10 @@ interface IFingerprintService { // hidlSensors must be non-null and empty. See AuthService.java void registerAuthenticators(in List hidlSensors); + // Adds a callback which gets called when the service registers all of the fingerprint + // authenticators. The callback is automatically removed after it's invoked. + void addAuthenticatorsRegisteredCallback(IFingerprintAuthenticatorsRegisteredCallback callback); + // Notifies about a finger touching the sensor area. void onPointerDown(int sensorId, int x, int y, float minor, float major); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 3d86034093423..179b077a3714c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -20,6 +20,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.Authenticators; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; @@ -39,6 +40,7 @@ import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -57,6 +59,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.inject.Inject; @@ -73,16 +76,13 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private static final String TAG = "AuthController"; private static final boolean DEBUG = true; + private final Handler mHandler = new Handler(Looper.getMainLooper()); private final CommandQueue mCommandQueue; private final StatusBarStateController mStatusBarStateController; private final ActivityTaskManager mActivityTaskManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; private final Provider mUdfpsControllerFactory; - - @Nullable private final List mFpProps; - @Nullable private final List mFaceProps; - @Nullable private final List mUdfpsProps; @Nullable private final PointF mFaceAuthSensorLocation; // TODO: These should just be saved from onSaveState @@ -90,7 +90,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @VisibleForTesting AuthDialog mCurrentDialog; - private Handler mHandler = new Handler(Looper.getMainLooper()); private WindowManager mWindowManager; @Nullable private UdfpsController mUdfpsController; @@ -98,6 +97,9 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, TaskStackListener mTaskStackListener; @VisibleForTesting IBiometricSysuiReceiver mReceiver; + @Nullable private final List mFaceProps; + @Nullable private List mFpProps; + @Nullable private List mUdfpsProps; private class BiometricTaskStackListener extends TaskStackListener { @Override @@ -106,8 +108,31 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } - @VisibleForTesting - final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @NonNull + private final IFingerprintAuthenticatorsRegisteredCallback + mFingerprintAuthenticatorsRegisteredCallback = + new IFingerprintAuthenticatorsRegisteredCallback.Stub() { + @Override public void onAllAuthenticatorsRegistered( + List sensors) { + if (DEBUG) { + Log.d(TAG, "onFingerprintProvidersAvailable | sensors: " + Arrays.toString( + sensors.toArray())); + } + mFpProps = sensors; + List udfpsProps = new ArrayList<>(); + for (FingerprintSensorPropertiesInternal props : mFpProps) { + if (props.isAnyUdfpsType()) { + udfpsProps.add(props); + } + } + mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; + if (mUdfpsProps != null) { + mUdfpsController = mUdfpsControllerFactory.get(); + } + } + }; + + @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mCurrentDialog != null @@ -348,19 +373,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mFaceManager = faceManager; mUdfpsControllerFactory = udfpsControllerFactory; - mFpProps = mFingerprintManager != null ? mFingerprintManager.getSensorPropertiesInternal() - : null; mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null; - List udfpsProps = new ArrayList<>(); - if (mFpProps != null) { - for (FingerprintSensorPropertiesInternal props : mFpProps) { - if (props.isAnyUdfpsType()) { - udfpsProps.add(props); - } - } - } - mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; int[] faceAuthLocation = context.getResources().getIntArray( com.android.systemui.R.array.config_face_auth_props); if (faceAuthLocation == null || faceAuthLocation.length < 2) { @@ -383,9 +397,9 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mCommandQueue.addCallback(this); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected() - && mUdfpsProps != null) { - mUdfpsController = mUdfpsControllerFactory.get(); + if (mFingerprintManager != null) { + mFingerprintManager.addAuthenticatorsRegisteredCallback( + mFingerprintAuthenticatorsRegisteredCallback); } mTaskStackListener = new BiometricTaskStackListener(); @@ -527,7 +541,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, return mFaceManager.hasEnrolledTemplates(userId); } - /** + /** * Whether the passed userId has enrolled UDFPS. */ public boolean isUdfpsEnrolled(int userId) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 3fe8cee8d7397..1b464a9b971b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -50,7 +50,9 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; +import android.os.RemoteException; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; @@ -66,6 +68,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.AdditionalMatchers; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -100,12 +103,13 @@ public class AuthControllerTest extends SysuiTestCase { private FaceManager mFaceManager; @Mock private UdfpsController mUdfpsController; + @Captor + ArgumentCaptor mAuthenticatorsRegisteredCaptor; private TestableAuthController mAuthController; - @Before - public void setup() { + public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); TestableContext context = spy(mContext); @@ -148,6 +152,9 @@ public class AuthControllerTest extends SysuiTestCase { () -> mUdfpsController); mAuthController.start(); + verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( + mAuthenticatorsRegisteredCaptor.capture()); + mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props); } // Callback tests diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 2b0637fe335a0..39b7a74caa52b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -50,6 +50,7 @@ import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintServiceReceiver; +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintClientActiveCallback; import android.hardware.fingerprint.IFingerprintService; import android.hardware.fingerprint.IFingerprintServiceReceiver; @@ -61,6 +62,7 @@ import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -71,6 +73,7 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.DumpUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.ServiceThread; @@ -99,14 +102,22 @@ 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; private final FingerprintServiceWrapper mServiceWrapper; - @NonNull private List mServiceProviders; + @NonNull private final List mServiceProviders; @NonNull private final FingerprintStateCallback mFingerprintStateCallback; + @GuardedBy("mLock") + @NonNull private final RemoteCallbackList + mAuthenticatorsRegisteredCallbacks; + + @GuardedBy("mLock") + @NonNull private final List mSensorProps; + /** * Registers FingerprintStateListener in list stored by FingerprintService * @param listener new FingerprintStateListener being added @@ -744,7 +755,7 @@ public class FingerprintService extends SystemService { @Override // Binder call public void resetLockout(IBinder token, int sensorId, int userId, - @Nullable byte [] hardwareAuthToken, String opPackageName) { + @Nullable byte[] hardwareAuthToken, String opPackageName) { Utils.checkPermission(getContext(), RESET_FINGERPRINT_LOCKOUT); final ServiceProvider provider = getProviderForSensor(sensorId); @@ -856,9 +867,39 @@ public class FingerprintService extends SystemService { } } } + + synchronized (mLock) { + for (ServiceProvider provider : mServiceProviders) { + mSensorProps.addAll(provider.getSensorProperties()); + } + } + + broadcastAllAuthenticatorsRegistered(); }); } + @Override + public void addAuthenticatorsRegisteredCallback( + IFingerprintAuthenticatorsRegisteredCallback callback) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + if (callback == null) { + Slog.e(TAG, "addAuthenticatorsRegisteredCallback, callback is null"); + return; + } + + 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"); + } + } + @Override public void onPointerDown(int sensorId, int x, int y, float minor, float major) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); @@ -870,6 +911,7 @@ public class FingerprintService extends SystemService { } provider.onPointerDown(sensorId, x, y, minor, major); } + @Override public void onPointerUp(int sensorId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); @@ -906,6 +948,40 @@ public class FingerprintService extends SystemService { mLockPatternUtils = new LockPatternUtils(context); mServiceProviders = new ArrayList<>(); mFingerprintStateCallback = new FingerprintStateCallback(); + mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>(); + mSensorProps = new ArrayList<>(); + } + + // 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 callbacks = new ArrayList<>(); + final List 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 @@ -950,12 +1026,9 @@ public class FingerprintService extends SystemService { @NonNull private List getSensorProperties() { - final List properties = new ArrayList<>(); - - for (ServiceProvider provider : mServiceProviders) { - properties.addAll(provider.getSensorProperties()); + synchronized (mLock) { + return mSensorProps; } - return properties; } @NonNull