blob: ece35c522ec7942a1e017bb8f4bd92affb6a7313 [file] [log] [blame]
/*
* 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.fingerprint;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
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.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricPrompt;
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;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
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;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
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.provider.Settings;
import android.util.EventLog;
import android.util.Pair;
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.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintProvider;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21UdfpsMock;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
* The service is responsible for maintaining a list of clients and dispatching all
* fingerprint-related events.
*/
public class FingerprintService extends SystemService {
protected static final String TAG = "FingerprintService";
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, FingerprintProvider> mFingerprintProvider;
@NonNull
private final BiometricStateCallback<ServiceProvider, FingerprintSensorPropertiesInternal>
mBiometricStateCallback;
@NonNull
private final Handler mHandler;
@NonNull
private final FingerprintServiceRegistry mRegistry;
/** Receives the incoming binder calls from FingerprintManager. */
@VisibleForTesting
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) {
super.createTestSession_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId);
return null;
}
return provider.createTestSession(sensorId, callback, opPackageName);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) {
super.dumpSensorServiceStateProto_enforcePermission();
final ProtoOutputStream proto = new ProtoOutputStream();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider != null) {
provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
proto.flush();
return proto.getBytes();
}
@Override // Binder call
public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(
@NonNull String opPackageName) {
if (getContext().checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL)
!= PackageManager.PERMISSION_GRANTED) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
return mRegistry.getAllProperties();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId,
@NonNull String opPackageName) {
super.getSensorProperties_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId
+ ", caller: " + opPackageName);
return null;
}
return provider.getSensorProperties(sensorId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public void generateChallenge(IBinder token, int sensorId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName) {
super.generateChallenge_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
return;
}
provider.scheduleGenerateChallenge(sensorId, userId, token, receiver, opPackageName);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName,
long challenge) {
super.revokeChallenge_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId);
return;
}
provider.scheduleRevokeChallenge(sensorId, userId, token, opPackageName,
challenge);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public long enroll(final IBinder token, @NonNull final byte[] hardwareAuthToken,
final int userId, final IFingerprintServiceReceiver receiver,
final String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
super.enroll_enforcePermission();
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for enroll");
return -1;
}
return provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
receiver, opPackageName, enrollReason);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public void cancelEnrollment(final IBinder token, long requestId) {
super.cancelEnrollment_enforcePermission();
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelEnrollment");
return;
}
provider.second.cancelEnrollment(provider.first, token, requestId);
}
@SuppressWarnings("deprecation")
@Override // Binder call
public long authenticate(
final IBinder token,
final long operationId,
final IFingerprintServiceReceiver receiver,
final FingerprintAuthenticateOptions options) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
final String opPackageName = options.getOpPackageName();
final String attributionTag = options.getAttributionTag();
final int userId = options.getUserId();
if (!canUseFingerprint(
opPackageName,
attributionTag,
true /* requireForeground */,
callingUid,
callingPid,
callingUserId)) {
Slog.w(TAG, "Authenticate rejecting package: " + opPackageName);
return -1;
}
// Keyguard check must be done on the caller's binder identity, since it also checks
// permission.
final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName);
// Clear calling identity when checking LockPatternUtils for StrongAuth flags.
final long identity1 = Binder.clearCallingIdentity();
try {
if (isKeyguard && Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
// If this happens, something in KeyguardUpdateMonitor is wrong.
// SafetyNet for b/79776455
EventLog.writeEvent(0x534e4554, "79776455");
Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown");
return -1;
}
} finally {
Binder.restoreCallingIdentity(identity1);
}
final boolean restricted = getContext().checkCallingPermission(MANAGE_FINGERPRINT)
!= PackageManager.PERMISSION_GRANTED;
final int statsClient = isKeyguard ? BiometricsProtoEnums.CLIENT_KEYGUARD
: BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
final Pair<Integer, ServiceProvider> provider;
if (options.getSensorId() == FingerprintManager.SENSOR_ID_ANY) {
provider = mRegistry.getSingleProvider();
} else {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
provider = new Pair<>(options.getSensorId(),
mRegistry.getProviderForSensor(options.getSensorId()));
}
if (provider == null) {
Slog.w(TAG, "Null provider for authenticate");
return -1;
}
options.setSensorId(provider.first);
final FingerprintSensorPropertiesInternal sensorProps =
provider.second.getSensorProperties(options.getSensorId());
if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
&& sensorProps != null && (sensorProps.isAnyUdfpsType()
|| sensorProps.isAnySidefpsType())) {
try {
return authenticateWithPrompt(operationId, sensorProps, callingUid,
callingUserId, receiver, opPackageName,
options.isIgnoreEnrollmentState());
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Invalid package", e);
return -1;
}
}
final long identity2 = Binder.clearCallingIdentity();
try {
VirtualDeviceManagerInternal vdm = getLocalService(
VirtualDeviceManagerInternal.class);
if (vdm != null) {
vdm.onAuthenticationPrompt(callingUid);
}
} finally {
Binder.restoreCallingIdentity(identity2);
}
return provider.second.scheduleAuthenticate(token, operationId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), options,
restricted, statsClient, isKeyguard);
}
private long authenticateWithPrompt(
final long operationId,
@NonNull final FingerprintSensorPropertiesInternal props,
final int uId,
final int userId,
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));
final Executor executor = context.getMainExecutor();
final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(promptContext)
.setTitle(context.getString(R.string.biometric_dialog_default_title))
.setSubtitle(context.getString(R.string.fingerprint_dialog_default_subtitle))
.setNegativeButton(
context.getString(R.string.cancel),
executor,
(dialog, which) -> {
try {
receiver.onError(
FINGERPRINT_ERROR_USER_CANCELED, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in negative button onClick()", e);
}
})
.setIsForLegacyFingerprintManager(props.sensorId)
.setIgnoreEnrollmentState(ignoreEnrollmentState)
.build();
final BiometricPrompt.AuthenticationCallback promptCallback =
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
try {
if (FingerprintUtils.isKnownErrorCode(errorCode)) {
receiver.onError(errorCode, 0 /* vendorCode */);
} else {
receiver.onError(FINGERPRINT_ERROR_VENDOR, errorCode);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in onAuthenticationError()", e);
}
}
@Override
public void onAuthenticationSucceeded(
BiometricPrompt.AuthenticationResult result) {
final Fingerprint fingerprint = new Fingerprint("", 0, 0L);
final boolean isStrong = props.sensorStrength == STRENGTH_STRONG;
try {
receiver.onAuthenticationSucceeded(fingerprint, userId, isStrong);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in onAuthenticationSucceeded()", e);
}
}
@Override
public void onAuthenticationFailed() {
try {
receiver.onAuthenticationFailed();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in onAuthenticationFailed()", e);
}
}
@Override
public void onAuthenticationAcquired(int acquireInfo) {
try {
if (FingerprintUtils.isKnownAcquiredCode(acquireInfo)) {
receiver.onAcquired(acquireInfo, 0 /* vendorCode */);
} else {
receiver.onAcquired(FINGERPRINT_ACQUIRED_VENDOR, acquireInfo);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in onAuthenticationAcquired()", e);
}
}
@Override
public void onAuthenticationHelp(int acquireInfo, CharSequence helpString) {
onAuthenticationAcquired(acquireInfo);
}
};
return biometricPrompt.authenticateForOperation(
new CancellationSignal(), executor, promptCallback, operationId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public long detectFingerprint(final IBinder token,
final IFingerprintServiceReceiver receiver,
final FingerprintAuthenticateOptions options) {
super.detectFingerprint_enforcePermission();
final String opPackageName = options.getOpPackageName();
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName);
return -1;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFingerprint");
return -1;
}
options.setSensorId(provider.first);
return provider.second.scheduleFingerDetect(token,
new ClientMonitorCallbackConverter(receiver), options,
BiometricsProtoEnums.CLIENT_KEYGUARD);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
@Override // Binder call
public void prepareForAuthentication(IBinder token, long operationId,
IBiometricSensorReceiver sensorReceiver,
@NonNull FingerprintAuthenticateOptions options,
long requestId, int cookie, boolean allowBackgroundAuthentication) {
super.prepareForAuthentication_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(options.getSensorId());
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
}
final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(token, operationId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), options, requestId,
restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
allowBackgroundAuthentication);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
@Override // Binder call
public void startPreparedClient(int sensorId, int cookie) {
super.startPreparedClient_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
}
provider.startPreparedClient(sensorId, cookie);
}
@Override // Binder call
public void cancelAuthentication(
final IBinder token,
final String opPackageName,
final String attributionTag,
long requestId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
if (!canUseFingerprint(
opPackageName,
attributionTag,
true /* requireForeground */,
callingUid,
callingPid,
callingUserId)) {
Slog.w(TAG, "cancelAuthentication rejecting package: " + opPackageName);
return;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthentication");
return;
}
provider.second.cancelAuthentication(provider.first, token, requestId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void cancelFingerprintDetect(final IBinder token, final String opPackageName,
final long requestId) {
super.cancelFingerprintDetect_enforcePermission();
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: "
+ opPackageName);
return;
}
// For IBiometricsFingerprint2.1, cancelling fingerprint detect is the same as
// cancelling authentication.
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for cancelFingerprintDetect");
return;
}
provider.second.cancelAuthentication(provider.first, token, requestId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_BIOMETRIC)
@Override // Binder call
public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
final String opPackageName, final long requestId) {
super.cancelAuthenticationFromService_enforcePermission();
Slog.d(TAG, "cancelAuthenticationFromService, sensorId: " + sensorId);
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
}
provider.cancelAuthentication(sensorId, token, requestId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public void remove(final IBinder token, final int fingerId, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) {
super.remove_enforcePermission();
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for remove");
return;
}
provider.second.scheduleRemove(provider.first, token, receiver, fingerId, userId,
opPackageName);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void removeAll(final IBinder token, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) {
super.removeAll_enforcePermission();
final FingerprintServiceReceiver internalReceiver = new FingerprintServiceReceiver() {
int sensorsFinishedRemoving = 0;
final int numSensors = getSensorPropertiesInternal(
getContext().getOpPackageName()).size();
@Override
public void onRemoved(Fingerprint fp, int remaining) throws RemoteException {
if (remaining == 0) {
sensorsFinishedRemoving++;
Slog.d(TAG, "sensorsFinishedRemoving: " + sensorsFinishedRemoving
+ ", numSensors: " + numSensors);
if (sensorsFinishedRemoving == numSensors) {
receiver.onRemoved(null, 0 /* remaining */);
}
}
}
};
// This effectively iterates through all sensors, but has to do so by finding all
// sensors under each provider.
for (ServiceProvider provider : mRegistry.getProviders()) {
List<FingerprintSensorPropertiesInternal> props = provider.getSensorProperties();
for (FingerprintSensorPropertiesInternal prop : props) {
provider.scheduleRemoveAll(prop.sensorId, token, internalReceiver, userId,
opPackageName);
}
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback,
final String opPackageName) {
super.addLockoutResetCallback_enforcePermission();
mLockoutResetDispatcher.addCallback(callback, opPackageName);
}
@Override // Binder call
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err, @NonNull String[] args,
@Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver)
throws RemoteException {
(new FingerprintShellCommand(getContext(), FingerprintService.this))
.exec(this, in, out, err, args, callback, resultReceiver);
}
@Override // Binder call
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
}
final long ident = Binder.clearCallingIdentity();
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 (FingerprintSensorPropertiesInternal 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 (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
provider.dumpProtoMetrics(props.sensorId, fd);
}
}
} else {
for (ServiceProvider provider : mRegistry.getProviders()) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
pw.println("Dumping for sensorId: " + props.sensorId
+ ", provider: " + provider.getClass().getSimpleName());
pw.println("Fps state: "
+ mBiometricStateCallback.getBiometricState());
provider.dumpInternal(props.sensorId, pw);
pw.println();
}
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override // Binder call
public boolean isHardwareDetectedDeprecated(String opPackageName, String attributionTag) {
if (!canUseFingerprint(
opPackageName,
attributionTag,
false /* foregroundOnly */,
Binder.getCallingUid(),
Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
return false;
}
final long token = Binder.clearCallingIdentity();
try {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetectedDeprecated, caller: "
+ opPackageName);
return false;
}
return provider.second.isHardwareDetected(provider.first);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public boolean isHardwareDetected(int sensorId, String opPackageName) {
super.isHardwareDetected_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
}
return provider.isHardwareDetected(sensorId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override // Binder call
public void rename(final int fingerId, final int userId, final String name) {
super.rename_enforcePermission();
if (!Utils.isCurrentUserOrProfile(getContext(), userId)) {
return;
}
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for rename");
return;
}
provider.second.rename(provider.first, fingerId, userId, name);
}
@Override // Binder call
public List<Fingerprint> getEnrolledFingerprints(
int userId, String opPackageName, String attributionTag) {
if (!canUseFingerprint(
opPackageName,
attributionTag,
false /* foregroundOnly */,
Binder.getCallingUid(),
Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
return Collections.emptyList();
}
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
return FingerprintService.this.getEnrolledFingerprintsDeprecated(userId, opPackageName);
}
@Override // Binder call
public boolean hasEnrolledFingerprintsDeprecated(
int userId, String opPackageName, String attributionTag) {
if (!canUseFingerprint(
opPackageName,
attributionTag,
false /* foregroundOnly */,
Binder.getCallingUid(),
Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
return false;
}
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
return !FingerprintService.this.getEnrolledFingerprintsDeprecated(userId, opPackageName)
.isEmpty();
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) {
super.hasEnrolledFingerprints_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for hasEnrolledFingerprints, caller: " + opPackageName);
return false;
}
return provider.getEnrolledFingerprints(sensorId, userId).size() > 0;
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
super.getLockoutModeForUser_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
}
return provider.getLockoutModeForUser(sensorId, userId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void invalidateAuthenticatorId(int sensorId, int userId,
IInvalidationCallback callback) {
super.invalidateAuthenticatorId_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for invalidateAuthenticatorId");
return;
}
provider.scheduleInvalidateAuthenticatorId(sensorId, userId, callback);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public long getAuthenticatorId(int sensorId, int userId) {
super.getAuthenticatorId_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
}
return provider.getAuthenticatorId(sensorId, userId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT)
@Override // Binder call
public void resetLockout(IBinder token, int sensorId, int userId,
@Nullable byte[] hardwareAuthToken, String opPackageName) {
super.resetLockout_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
}
provider.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override
public boolean isClientActive() {
super.isClientActive_enforcePermission();
return mGestureAvailabilityDispatcher.isAnySensorActive();
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override
public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
super.addClientActiveCallback_enforcePermission();
mGestureAvailabilityDispatcher.registerCallback(callback);
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_FINGERPRINT)
@Override
public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
super.removeClientActiveCallback_enforcePermission();
mGestureAvailabilityDispatcher.removeCallback(callback);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override // Binder call
public void registerAuthenticators(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
super.registerAuthenticators_enforcePermission();
mRegistry.registerAll(() -> {
final List<ServiceProvider> providers = new ArrayList<>();
providers.addAll(getHidlProviders(hidlSensors));
List<String> aidlSensors = new ArrayList<>();
final String[] instances = mAidlInstanceNameSupplier.get();
if (instances != null) {
aidlSensors.addAll(Lists.newArrayList(instances));
}
providers.addAll(getAidlProviders(
Utils.filterAvailableHalInstances(getContext(), aidlSensors)));
return providers;
});
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void addAuthenticatorsRegisteredCallback(
IFingerprintAuthenticatorsRegisteredCallback callback) {
super.addAuthenticatorsRegisteredCallback_enforcePermission();
mRegistry.addAllRegisteredCallback(callback);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
super.registerBiometricStateListener_enforcePermission();
mBiometricStateCallback.registerBiometricStateListener(listener);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onPointerDown(long requestId, int sensorId, PointerContext pc) {
super.onPointerDown_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
return;
}
provider.onPointerDown(requestId, sensorId, pc);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onPointerUp(long requestId, int sensorId, PointerContext pc) {
super.onPointerUp_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
return;
}
provider.onPointerUp(requestId, sensorId, pc);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onUiReady(long requestId, int sensorId) {
super.onUiReady_enforcePermission();
final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
return;
}
provider.onUiReady(requestId, sensorId);
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
super.setUdfpsOverlayController_enforcePermission();
for (ServiceProvider provider : mRegistry.getProviders()) {
provider.setUdfpsOverlayController(controller);
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
super.setSidefpsController_enforcePermission();
for (ServiceProvider provider : mRegistry.getProviders()) {
provider.setSidefpsController(controller);
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) {
super.setUdfpsOverlay_enforcePermission();
for (ServiceProvider provider : mRegistry.getProviders()) {
provider.setUdfpsOverlay(controller);
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void onPowerPressed() {
super.onPowerPressed_enforcePermission();
for (ServiceProvider provider : mRegistry.getProviders()) {
provider.onPowerPressed();
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void scheduleWatchdog() {
super.scheduleWatchdog_enforcePermission();
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for scheduling watchdog");
return;
}
provider.second.scheduleWatchdog(provider.first);
}
};
public FingerprintService(Context context) {
this(context, BiometricContext.getInstance(context),
() -> IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
() -> ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR),
null /* fingerprintProvider */);
}
@VisibleForTesting
FingerprintService(Context context,
BiometricContext biometricContext,
Supplier<IBiometricService> biometricServiceSupplier,
Supplier<String[]> aidlInstanceNameSupplier,
Function<String, FingerprintProvider> fingerprintProvider) {
super(context);
mBiometricContext = biometricContext;
mAidlInstanceNameSupplier = aidlInstanceNameSupplier;
mAppOps = context.getSystemService(AppOpsManager.class);
mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
mFingerprintProvider = fingerprintProvider != null ? fingerprintProvider :
(name) -> {
final String fqName = IFingerprint.DESCRIPTOR + "/" + name;
final IFingerprint fp = IFingerprint.Stub.asInterface(
Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName)));
if (fp != null) {
try {
return new FingerprintProvider(getContext(),
mBiometricStateCallback, fp.getSensorProps(), name,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
mBiometricContext);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
} else {
Slog.e(TAG, "Unable to get declared service: " + fqName);
}
return null;
};
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(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
final List<ServiceProvider> providers = new ArrayList<>();
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(),
mBiometricStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
BiometricContext.getInstance(getContext()));
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(),
mBiometricStateCallback, hidlSensor, mHandler,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
providers.add(fingerprint21);
}
return providers;
}
@NonNull
private List<ServiceProvider> getAidlProviders(@NonNull List<String> instances) {
final List<ServiceProvider> providers = new ArrayList<>();
for (String instance : instances) {
final FingerprintProvider provider = mFingerprintProvider.apply(instance);
Slog.i(TAG, "Adding AIDL provider: " + instance);
providers.add(provider);
}
return providers;
}
@Override
public void onStart() {
publishBinderService(Context.FINGERPRINT_SERVICE, mServiceWrapper);
}
@NonNull
private List<Fingerprint> getEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for getEnrolledFingerprintsDeprecated, caller: "
+ opPackageName);
return Collections.emptyList();
}
return provider.second.getEnrolledFingerprints(provider.first, userId);
}
/** Checks for public API invocations to ensure that permissions, etc are granted/correct. */
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean canUseFingerprint(
String opPackageName,
String attributionTag,
boolean requireForeground,
int uid,
int pid,
int userId) {
if (getContext().checkCallingPermission(USE_FINGERPRINT)
!= PackageManager.PERMISSION_GRANTED) {
Utils.checkPermission(getContext(), USE_BIOMETRIC);
}
if (Binder.getCallingUid() == Process.SYSTEM_UID) {
return true; // System process (BiometricService, etc) is always allowed
}
if (Utils.isKeyguard(getContext(), opPackageName)) {
return true;
}
if (!Utils.isCurrentUserOrProfile(getContext(), userId)) {
Slog.w(TAG, "Rejecting " + opPackageName + "; not a current user or profile");
return false;
}
if (!checkAppOps(uid, opPackageName, attributionTag)) {
Slog.w(TAG, "Rejecting " + opPackageName + "; permission denied");
return false;
}
if (requireForeground && !Utils.isForeground(uid, pid)) {
Slog.w(TAG, "Rejecting " + opPackageName + "; not in foreground");
return false;
}
return true;
}
private boolean checkAppOps(int uid, String opPackageName, String attributionTag) {
boolean appOpsOk = false;
if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid, opPackageName, attributionTag, null)
== AppOpsManager.MODE_ALLOWED) {
appOpsOk = true;
} else if (mAppOps.noteOp(
AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName, attributionTag, null)
== AppOpsManager.MODE_ALLOWED) {
appOpsOk = true;
}
return appOpsOk;
}
void syncEnrollmentsNow() {
Utils.checkPermissionOrShell(getContext(), MANAGE_FINGERPRINT);
if (Utils.isVirtualEnabled(getContext())) {
Slog.i(TAG, "Sync virtual enrollments");
final int userId = ActivityManager.getCurrentUser();
final CountDownLatch latch = new CountDownLatch(mRegistry.getProviders().size());
for (ServiceProvider provider : mRegistry.getProviders()) {
for (FingerprintSensorPropertiesInternal props : provider.getSensorProperties()) {
provider.scheduleInternalCleanup(props.sensorId, userId,
new ClientMonitorCallback() {
@Override
public void onClientFinished(
@NonNull BaseClientMonitor clientMonitor,
boolean success) {
latch.countDown();
if (!success) {
Slog.e(TAG, "Sync virtual enrollments failed");
}
}
}, true /* favorHalEnrollments */);
}
}
try {
latch.await(3, TimeUnit.SECONDS);
} catch (Exception e) {
Slog.e(TAG, "Failed to wait for sync finishing", e);
}
}
}
}