1 指纹的启动流程
我们直接从kernel启动开始看。
1.1 指纹驱动的启动
Linux内核开始启动,初始化各种软硬件环境,加载驱动程序,挂载根文件系统,在系统文件中寻找init.rc文件,并启动init进程。Kernel中,加载指纹驱动,根据传入的dts信息创建设备节点,注册设备。
1.2 hal服务启动
然后在Init启动后,初始化和启动属性服务,并且启动Zygote进程。然后找到android.hardware.biometrics.fingerprint@2.1-service.rc,启动android.hardware.biometrics.fingerprint@2.1-service,会去open fingerprint.deault.so,等待与上层通信。
service vendor.fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2.1-service
# "class hal" causes a race condition on some devices due to files created
# in /data. As a workaround, postpone startup until later in boot once
# /data is mounted.
class late_start
user system
group system input uhid
task_profiles ServiceCapacityLow
会使位于系统vendor/bin/hw下的android.hardware.biometrics.fingerprint@2.1-service(以下简称2.1 bin)开机自启动,启动后会注册2.1 service,该bin服务对应的代码在:hardware/interfaces/biometrics/fingerprint/2.1/default/service.cpp。
int main() {
android::sp<IBiometricsFingerprint> bio = BiometricsFingerprint::getInstance();
configureRpcThreadpool(1, true /*callerWillJoin*/);
if (bio != nullptr) {
if (::android::OK != bio->registerAsService()) {
return 1;
}
} else {
ALOGE("Can't create instance of BiometricsFingerprint, nullptr");
}
joinRpcThreadpool();
return 0; // should never get here
}
整个注册过程只有两步,首先实例化传入的 IBiometricsFingerprint 接口对象,然后通过 registerAsService 将服务注册到 hwservicemanager。
这里BiometricsFingerprint后面会分析。
1.3 Fingerprintservice启动
等待Zygote进程启动,创建java虚拟机并为java虚拟机注册JNI方法,创建服务器端Socket,启动SystemServer进程。
SystemServer进程启动,启动Binder线程池和SystemServiceManager,并且启动各种系统服务。会启动Fingerprintservice。
//framework/base/services/java/com/android/server/SystemServer.java
private void run() {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
...
startOtherServices(t);
...
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
final boolean hasFeatureFingerprint =
mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
if (hasFeatureFingerprint) {
t.traceBegin("StartFingerprintSensor");
final FingerprintService fingerprintService =
mSystemServiceManager.startService(FingerprintService.class);
t.traceEnd();
}
}
再来看SystemServiceManager#startService
//framework/base/services/core/java/com/android/server/SystemServiceManager.java
public SystemService startService(String className) {
final Class<SystemService> serviceClass = loadClassFromLoader(className,
this.getClass().getClassLoader());
return startService(serviceClass);
}
private static Class<SystemService> loadClassFromLoader(String className,
ClassLoader classLoader) {
try {
return (Class<SystemService>) Class.forName(className, true, classLoader);
}
}
public <T extends SystemService> T startService(Class<T> serviceClass) {
final T service;
try {
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
}
...
startService(service);
return service;
}
public void startService(@NonNull final SystemService service) {
// Check if already started
String className = service.getClass().getName();
if (mServiceClassnames.contains(className)) {
Slog.i(TAG, "Not starting an already started service " + className);
return;
}
mServiceClassnames.add(className);
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service "
+ service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
可以看到会反射创建这个类的构造方法并把它添加到services中,接着执行这个类的onStart方法.
因此,我们来看FingerprintService的onStart方法。
@Override
public void onStart() {
publishBinderService(Context.FINGERPRINT_SERVICE, mServiceWrapper);
}
最终调用到了SystemService#publishBinderService
//framework/base/services/core/java/com/android/server/SystemService.java
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated, int dumpPriority) {
ServiceManager.addService(name, service, allowIsolated, dumpPriority);
}
注册的服务接口
/** Receives the incoming binder calls from FingerprintManager. */
final IFingerprintService.Stub mServiceWrapper = new IFingerprintService.Stub() {
@Override // Binder call
public long enroll() {}
@Override // Binder call
public long authenticate(){}
}
这样就可以提供指纹服务给客户端。
1.4 总结
具有系统权限的client下发注册命令->FingerprintManager收到命令->FingerprintService收到命令->(2.1 service)BiometricsFingerprint收到命令->(fingerprint.default.so)Fingerprint.cpp收到命令->指纹CA收到命令->指纹TA收到命令->SPI采集数据\算法进行注册等
2 指纹录入
指纹录入的入口在Settings中,其重要负责指纹录入一些UI的加载和一些录入动画的逻辑。
2.1 指纹录入
先来看录入的入口类FingerprintEnrollEnrolling
。
public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling
- public abstract class BiometricsEnrollEnrolling extends BiometricEnrollBase
- public abstract class BiometricEnrollBase extends InstrumentedActivity
- public abstract class InstrumentedActivity extends ObservableActivity
- public class ObservableActivity extends FragmentActivity
- androidx.fragment.app.FragmentActivity;
从继承关系可以看到FingerprintEnrollEnrolling与人脸基本是一样的。
//packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
/**
* Activity which handles the actual enrolling for fingerprint.
*/
public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
}
同样的,FingerprintEnrollEnrolling也是一个activity。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final FingerprintManager fingerprintManager =
getSystemService(FingerprintManager.class);
final List<FingerprintSensorPropertiesInternal> props =
fingerprintManager.getSensorPropertiesInternal();
mCanAssumeUdfps = props.size() == 1 && props.get(0).isAnyUdfpsType();
if (mCanAssumeUdfps) {
if (BiometricUtils.isReverseLandscape(getApplicationContext())) {
setContentView(R.layout.udfps_enroll_enrolling_land);
} else {
setContentView(R.layout.udfps_enroll_enrolling);
}
setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
} else {
setContentView(R.layout.fingerprint_enroll_enrolling);
setDescriptionText(
R.string.security_settings_fingerprint_enroll_start_message);
}
....
}
我们看这里的startEnrollment
@Override
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
if (mCanAssumeUdfps) {
startEnrollment();
}
mAnimationCancelled = false;
startIconAnimation();
}
这里调到了FingerprintEnrollSidecar#startEnrollment录入的方法
@Override
protected void startEnrollment() {
super.startEnrollment();
if (mToken == null) {
Log.e(TAG, "Null hardware auth token for enroll");
onEnrollmentError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
getString(R.string.fingerprint_intro_error_unknown));
return;
}
mFingerprintManager.enroll(
mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
mEnrollReason);
}
startEnrollment
里面直接调用FingerprintManager#enroll。我们先看看这个mEnrollmentCallback有啥。
private FingerprintManager.EnrollmentCallback mEnrollmentCallback
= new FingerprintManager.EnrollmentCallback() {
@Override
public void onEnrollmentProgress(int remaining) {
FingerprintEnrollSidecar.super.onEnrollmentProgress(remaining);
}
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
FingerprintEnrollSidecar.super.onEnrollmentHelp(helpMsgId, helpString);
}
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
FingerprintEnrollSidecar.super.onEnrollmentError(errMsgId, errString);
}
};
这里主要是录入进度、提示信息、录入错误等回调。
再来看frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java的enrol,到这里就正式进入系统流程了。
/**
* Request fingerprint enrollment. This call warms up the fingerprint hardware
* and starts scanning for fingerprints. Progress will be indicated by callbacks to the
* {@link EnrollmentCallback} object. It terminates when
* {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
* {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
* which point the object is no longer valid. The operation can be canceled by using the
* provided cancel object.
* @param token a unique token provided by a recent creation or verification of device
* credentials (e.g. pin, pattern or password).
* @param cancel an object that can be used to cancel enrollment
* @param flags optional flags
* @param userId the user to whom this fingerprint will belong to
* @param callback an object to receive enrollment events
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] token, CancellationSignal cancel, int flags,
int userId, EnrollmentCallback callback) {
if (userId == UserHandle.USER_CURRENT) {
userId = getCurrentUserId();
}
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
}
if (cancel != null) {
if (cancel.isCanceled()) {
Slog.w(TAG, "enrollment already canceled");
return;
} else {
cancel.setOnCancelListener(new OnEnrollCancelListener());
}
}
if (mService != null) try {
mEnrollmentCallback = callback;
mService.enroll(mToken, token, userId, mServiceReceiver, flags,
mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enroll: ", e);
if (callback != null) {
// Though this may not be a hardware issue,
// it will cause apps to give up or try again later.
callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */));
}
}
}
这里直接调用的FaceService#enroll
,继续往下看。
/**
* Receives the incoming binder calls from FingerprintManager.
*/
@Override // Binder call
public void enroll(final IBinder token, final byte[] cryptoToken, final int userId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
checkPermission(MANAGE_FINGERPRINT);
final boolean restricted = isRestricted();
final int groupId = userId; // default group for fingerprint enrollment
final EnrollClientImpl client = new EnrollClientImpl(getContext(),
mDaemonWrapper, mHalDeviceId, token,
new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
cryptoToken, restricted, opPackageName,
new int[0] /* disabledFeatures */, ENROLL_TIMEOUT_SEC) {
@Override
public boolean shouldVibrate() {
return true;
}
@Override
protected int statsModality() {
return FingerprintService.this.statsModality();
}
};
enrollInternal(client, userId);
}
这里先检查有没有MANAGE_FINGERPRINT的权限,然后向构建了EnrollClientImpl,我们知道后面接收录入进度全靠这个类了。
这里重点是enrollInternal。
//framework/base/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
/**
* Calls from the Manager. These are still on the calling binder's thread.
*/
protected void enrollInternal(EnrollClientImpl client, int userId) {
if (hasReachedEnrollmentLimit(userId)) {
return;
}
// Group ID is arbitrarily set to parent profile user ID. It just represents
// the default biometrics for the user.
if (!isCurrentUserOrProfile(userId)) {
return;
}
mHandler.post(() -> {
startClient(client, true /* initiatedByClient */);
});
}
enrollInternal首先检查指纹录入的数量是否达到限制。
@Override
protected boolean hasReachedEnrollmentLimit(int userId) {
final int limit = getContext().getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
final int enrolled = FingerprintService.this.getEnrolledTemplates(userId).size();
if (enrolled >= limit) {
Slog.w(TAG, "Too many fingerprints registered");
return true;
}
return false;
}
对比的方法是将res配置的数量和已经录入的进行对比。
<!-- For performance and storage reasons, limit the number of fingerprints per user -->
<integer name="config_fingerprintMaxTemplatesPerUser">5</integer>
从res可以看到,对于指纹来说,这个最大配置个数为5。
最后从binder线程,切换到主线程中执行startClient。
/**
* Calls the HAL to switch states to the new task. If there's already a current task,
* it calls cancel() and sets mPendingClient to begin when the current task finishes
* ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
*
* @param newClient the new client that wants to connect
* @param initiatedByClient true for authenticate, remove and enroll
*/
@VisibleForTesting
void startClient(ClientMonitor newClient, boolean initiatedByClient) {
ClientMonitor currentClient = mCurrentClient;
if (currentClient != null) {
if (DEBUG) Slog.v(getTag(), "request stop current client " +
currentClient.getOwnerString());
// This check only matters for FingerprintService, since enumerate may call back
// multiple times.
if (currentClient instanceof InternalEnumerateClient
|| currentClient instanceof InternalRemovalClient) {
// This condition means we're currently running internal diagnostics to
// remove extra templates in the hardware and/or the software
// TODO: design an escape hatch in case client never finishes
if (newClient != null) {
Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
+ newClient.getClass().getSuperclass().getSimpleName()
+ "(" + newClient.getOwnerString() + ")"
+ ", initiatedByClient = " + initiatedByClient);
}
} else {
currentClient.stop(initiatedByClient);
// Only post the reset runnable for non-cleanup clients. Cleanup clients should
// never be forcibly stopped since they ensure synchronization between HAL and
// framework. Thus, we should instead just start the pending client once cleanup
// finishes instead of using the reset runnable.
mHandler.removeCallbacks(mResetClientState);
mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
}
mPendingClient = newClient;
} else if (newClient != null) {
// For BiometricPrompt clients, do not start until
// <Biometric>Service#startPreparedClient is called. BiometricService waits until all
// modalities are ready before initiating authentication.
if (newClient instanceof AuthenticationClient) {
AuthenticationClient client = (AuthenticationClient) newClient;
if (client.isBiometricPrompt()) {
if (DEBUG) Slog.v(getTag(), "Returning cookie: " + client.getCookie());
mCurrentClient = newClient;
if (mBiometricService == null) {
mBiometricService = IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE));
}
try {
mBiometricService.onReadyForAuthentication(client.getCookie(),
client.getRequireConfirmation(), client.getTargetUserId());
} catch (RemoteException e) {
Slog.e(getTag(), "Remote exception", e);
}
return;
}
}
// We are not a BiometricPrompt client, start the client immediately
mCurrentClient = newClient;
startCurrentClient(mCurrentClient.getCookie());
}
}
这里如果已经有task,就先cancel调当前的,然后将newClient设置到mPendingClient,并设置一个3s的延迟消息来延迟执行mPendingClient,最后执行startCurrentClient。
protected void startCurrentClient(int cookie) {
if (mCurrentClient == null) {
Slog.e(getTag(), "Trying to start null client!");
return;
}
if (DEBUG) Slog.v(getTag(), "starting client "
+ mCurrentClient.getClass().getSuperclass().getSimpleName()
+ "(" + mCurrentClient.getOwnerString() + ")"
+ " targetUserId: " + mCurrentClient.getTargetUserId()
+ " currentUserId: " + mCurrentUserId
+ " cookie: " + cookie + "/" + mCurrentClient.getCookie());
if (cookie != mCurrentClient.getCookie()) {
Slog.e(getTag(), "Mismatched cookie");
return;
}
int status = mCurrentClient.start();
if (status == 0) {
notifyClientActiveCallbacks(true);
} else {
mCurrentClient.onError(getHalDeviceId(), BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
removeClient(mCurrentClient);
}
}
还是把mCurrentClient的对象传进去了。然后是 mCurrentClient.start()。
//frameworks/base/services/core/java/com/android/server/biometrics/EnrollClient.java
@Override
public int start() {
mEnrollmentStartTimeMs = System.currentTimeMillis();
try {
final ArrayList<Integer> disabledFeatures = new ArrayList<>();
for (int i = 0; i < mDisabledFeatures.length; i++) {
disabledFeatures.add(mDisabledFeatures[i]);
}
final int result = getDaemonWrapper().enroll(
mCryptoToken, getGroupId(), mTimeoutSec,disabledFeatures);
if (result != 0) {
Slog.w(getLogTag(), "startEnroll failed, result=" + result);
mMetricsLogger.histogram(mConstants.tagEnrollStartError(), result);
onError(getHalDeviceId(),
BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
return result;
}
} catch (RemoteException e) {
Slog.e(getLogTag(), "startEnroll failed", e);
}
return 0; // success
}
EnrollClient#start方法会通过getDaemonWrapper().enroll调用底层,调用底层的指纹库,底层库返回结果后会调用onEnrollResult来反馈结果receiver,再往上层反馈。这就是指纹的录制流程。
2.2 录入进度
在onEnrollResult中当remaining等于0的时候完成录制,调用addBiometricForUser。
FingerprintManager.java中注册了 IFingerprintServiceReceiver,实现onEnrollResult方法发送 MSG_ENROLL_RESULT
//frameworks/base/core/java/android/hardware/fingerprint/FingerprintManager.java
private IFingerprintServiceReceiver mServiceReceiver =
new IFingerprintServiceReceiver.Stub() {
@Override // binder call
public void onEnrollResult(long deviceId, int fingerId, int groupId,
int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
}
}
private class MyHandler extends Handler {
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_ENROLL_RESULT:
sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
break;
}
}
}
private void sendEnrollResult(Fingerprint fp, int remaining) {
if (mEnrollmentCallback != null) {
mEnrollmentCallback.onEnrollmentProgress(remaining);
}
}
在前面FingerprintEnrollEnrolling类中的onEnrollmentProgressChange(int steps, int remaining)更新录入进度的方法中用通过传递进来的remaining来获取实际的进度;最后当进度条达到最大值时打开录入结束界launchFinish(mToken)
///packages/apps/Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@Override
public void onEnrollmentProgressChange(int steps, int remaining) {
updateProgress(true /* animate */);
updateTitleAndDescription();
clearError();
animateFlash();
...
}
这里更新了进度条、背景图、提示语等,具体的就不看了。
2.3 Android 12流程
上面的流程中,Android高版本上有一些差异,我们从FingerprintService开始。
@Override // Binder call
public void enroll(final IBinder token, @NonNull final byte[] hardwareAuthToken,
final int userId, final IFingerprintServiceReceiver receiver,
final String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for enroll");
return;
}
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
receiver, opPackageName, enrollReason, mFingerprintStateCallback);
}
这里provider.second.scheduleEnroll我们一层一层拆解,先看getSingleProvider
@Nullable
private Pair<Integer, ServiceProvider> getSingleProvider() {
final List<FingerprintSensorPropertiesInternal> properties =
getSensorProperties();
if (properties.isEmpty()) {
Slog.e(TAG, "No providers found");
return null;
}
// Theoretically we can just return the first provider,
// but maybe this is easier to understand.
final int sensorId = properties.get(0).sensorId;
for (ServiceProvider provider : mServiceProviders) {
if (provider.containsSensor(sensorId)) {
return new Pair<>(sensorId, provider);
}
}
Slog.e(TAG, "Provider not found");
return null;
}
可以看到,getSingleProvider是一个Pair<Integer, ServiceProvider>,所以provider.second就是去取Pair的第二个元素,也就是ServiceProvider。getSingleProvider就是去找到匹配的ServiceProvider。它是从mServiceProviders中去找的,那么mServiceProviders是什么时候赋值的呢?
private void addHidlProviders(List<FingerprintSensorPropertiesInternal> 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(Binder.allowBlocking(
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);
}
}
}
这里有AIDL和HIDL的两种实现,我们选HIDL实现来看,它实际上就是调用Fingerprint21对象实例。
/**
* Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or
* its extended minor versions.
*/
public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider {
@Override
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver,
@NonNull String opPackageName,
@FingerprintManager.EnrollReason int enrollReason,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
final FingerprintEnrollClient client = new FingerprintEnrollClient(
mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId,
hardwareAuthToken, opPackageName,
FingerprintUtils.getLegacyInstance(mSensorId),
ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId,
mUdfpsOverlayController, mSidefpsController, enrollReason);
mScheduler.scheduleClientMonitor(client,
new BaseClientMonitor.Callback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
fingerprintStateCallback.onClientStarted(clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
fingerprintStateCallback.onClientFinished(clientMonitor, success);
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(
clientMonitor.getTargetUserId(), true /* force */);
}
}
});
});
}
}
直接看mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback()。mScheduler是一个BiometricScheduler对象,实际上是调用类BiometricScheduler下的方法scheduleClientMonitor。
/**
* Adds a {@link BaseClientMonitor} to the pending queue
*
* @param clientMonitor operation to be scheduled
* @param clientCallback optional callback, invoked when the client state changes.
*/
public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
@Nullable BaseClientMonitor.Callback clientCallback) {
// If the incoming operation should interrupt preceding clients,
// mark any interruptable pending clients as canceling.
// Once they reach the head of the queue, the scheduler will
// send ERROR_CANCELED and skip the operation.
if (clientMonitor.interruptsPrecedingClients()) {
for (Operation operation : mPendingOperations) {
if (operation.mClientMonitor instanceof Interruptable
&& operation.mState != Operation.STATE_WAITING_IN_QUEUE_CANCELING) {
Slog.d(getTag(), "New client incoming, marking pending client as canceling: " + operation.mClientMonitor);
operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING;
}
}
}
mPendingOperations.add(new Operation(clientMonitor, clientCallback));
Slog.d(getTag(), "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());
// If the new operation should interrupt preceding clients, and if the current operation is
// cancellable, start the cancellation process.
if (clientMonitor.interruptsPrecedingClients()
&& mCurrentOperation != null
&& mCurrentOperation.mClientMonitor instanceof Interruptable
&& mCurrentOperation.mState == Operation.STATE_STARTED) {
Slog.d(getTag(), "[Cancelling Interruptable]: " + mCurrentOperation);
cancelInternal(mCurrentOperation);
}
startNextOperationIfIdle();
}
我们先直接看startNextOperationIfIdle
protected void startNextOperationIfIdle() {
if (mCurrentOperation != null) {
Slog.v(getTag(), "Not idle, current operation: " + mCurrentOperation);
return;
}
if (mPendingOperations.isEmpty()) {
Slog.d(getTag(), "No operations, returning to idle");
return;
}
mCurrentOperation = mPendingOperations.poll();
final BaseClientMonitor currentClient = mCurrentOperation.mClientMonitor;
Slog.d(getTag(), "[Polled] " + mCurrentOperation);
// If the operation at the front of the queue has been marked for cancellation, send
// ERROR_CANCELED. No need to start this client.
if (mCurrentOperation.mState == Operation.STATE_WAITING_IN_QUEUE_CANCELING) {
Slog.d(getTag(), "[Now Cancelling] " + mCurrentOperation);
if (!(currentClient instanceof Interruptable)) {
throw new IllegalStateException("Mis-implemented client or scheduler, "
+ "trying to cancel non-interruptable operation: " + mCurrentOperation);
}
final Interruptable interruptable = (Interruptable) currentClient;
interruptable.cancelWithoutStarting(getInternalCallback());
// Now we wait for the client to send its FinishCallback, which kicks off the next
// operation.
return;
}
if (mGestureAvailabilityDispatcher != null
&& mCurrentOperation.mClientMonitor instanceof AcquisitionClient) {
mGestureAvailabilityDispatcher.markSensorActive(
mCurrentOperation.mClientMonitor.getSensorId(),
true /* active */);
}
// Not all operations start immediately. BiometricPrompt waits for its operation
// to arrive at the head of the queue, before pinging it to start.
final boolean shouldStartNow = currentClient.getCookie() == 0;
if (shouldStartNow) {
if (mCurrentOperation.isUnstartableHalOperation()) {
final HalClientMonitor<?> halClientMonitor =
(HalClientMonitor<?>) mCurrentOperation.mClientMonitor;
// Note down current length of queue
final int pendingOperationsLength = mPendingOperations.size();
final Operation lastOperation = mPendingOperations.peekLast();
Slog.e(getTag(), "[Unable To Start] " + mCurrentOperation
+ ". Last pending operation: " + lastOperation);
// For current operations, 1) unableToStart, which notifies the caller-side, then
// 2) notify operation's callback, to notify applicable system service that the
// operation failed.
halClientMonitor.unableToStart();
if (mCurrentOperation.mClientCallback != null) {
mCurrentOperation.mClientCallback.onClientFinished(
mCurrentOperation.mClientMonitor, false /* success */);
}
// Then for each operation currently in the pending queue at the time of this
// failure, do the same as above. Otherwise, it's possible that something like
// setActiveUser fails, but then authenticate (for the wrong user) is invoked.
for (int i = 0; i < pendingOperationsLength; i++) {
final Operation operation = mPendingOperations.pollFirst();
if (operation == null) {
Slog.e(getTag(), "Null operation, index: " + i
+ ", expected length: " + pendingOperationsLength);
break;
}
if (operation.isHalOperation()) {
((HalClientMonitor<?>) operation.mClientMonitor).unableToStart();
}
if (operation.mClientCallback != null) {
operation.mClientCallback.onClientFinished(operation.mClientMonitor,
false /* success */);
}
Slog.w(getTag(), "[Aborted Operation] " + operation);
}
// It's possible that during cleanup a new set of operations came in. We can try to
// run these. A single request from the manager layer to the service layer may
// actually be multiple operations (i.e. updateActiveUser + authenticate).
mCurrentOperation = null;
startNextOperationIfIdle();
} else {
Slog.d(getTag(), "[Starting] " + mCurrentOperation);
currentClient.start(getInternalCallback());
mCurrentOperation.mState = Operation.STATE_STARTED;
}
} else {
try {
mBiometricService.onReadyForAuthentication(currentClient.getCookie());
} catch (RemoteException e) {
Slog.e(getTag(), "Remote exception when contacting BiometricService", e);
}
Slog.d(getTag(), "Waiting for cookie before starting: " + mCurrentOperation);
mCurrentOperation.mState = Operation.STATE_WAITING_FOR_COOKIE;
}
}
这段比较长,先看currentClient.start(getInternalCallback());
要知道下一步怎么走,我们需要知道是怎么来的。
mCurrentOperation = mPendingOperations.poll();
final BaseClientMonitor currentClient = mCurrentOperation.mClientMonitor;
mCurrentOperation想从mPendingOperations中取到的,这个在前面scheduleClientMonitor中看到过。
mPendingOperations.add(new Operation(clientMonitor, clientCallback));
Slog.d(getTag(), "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());
Operation(
@NonNull BaseClientMonitor clientMonitor,
@Nullable BaseClientMonitor.Callback callback
) {
this(clientMonitor, callback, STATE_WAITING_IN_QUEUE);
}
所以,上面currentClient就是clientMonitor的实例,而clientMonitor从前面可以知道,是从scheduleClientMonitor传递过来的。
public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
@Nullable BaseClientMonitor.Callback clientCallback)
那我们只能回头去看看这个clientMonitor怎么来的。
final FingerprintEnrollClient client = new FingerprintEnrollClient(
mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId,
hardwareAuthToken, opPackageName,
FingerprintUtils.getLegacyInstance(mSensorId),
ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId,
mUdfpsOverlayController, mSidefpsController, enrollReason);
可以看到,它是在Fingerprint21的scheduleEnroll方法定义的。
到这里我们就明白了,currentClient.start(getInternalCallback())
;实际调用的是FingerprintEnrollClient的start方法。
public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint> implements Udfps
但是在FingerprintEnrollClient类中我们并没有看到有start方法,因此,我们在其父类中找找看。
@Override
public void start(@NonNull Callback callback) {
super.start(callback);
if (hasReachedEnrollmentLimit()) {
Slog.e(TAG, "Reached enrollment limit");
callback.onClientFinished(this, false /* success */);
return;
}
mEnrollmentStartTimeMs = System.currentTimeMillis();
startHalOperation();
}
果然,在父类EnrollClient中有start方法,直接看startHalOperation()。
@Override
protected void startHalOperation() {
mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason), this);
BiometricNotificationUtils.cancelBadCalibrationNotification(getContext());
try {
mCancellationSignal = getFreshDaemon().enroll(
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_UNABLE_TO_PROCESS,
0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
}
}
这个startHalOperation
是调用的FingerprintEnrollClient#startHalOperation
然后是getFreshDaemon().enroll(HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
//frameworks/base/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
/**
* Abstract {@link BaseClientMonitor} implementation that supports HAL operations.
* @param <T> HAL template
*/
public abstract class HalClientMonitor<T> extends BaseClientMonitor {
/**
* Interface that allows ClientMonitor subclasses to retrieve a fresh instance to the HAL.
*/
public interface LazyDaemon<T> {
/**
* @return A fresh instance to the biometric HAL
*/
T getDaemon();
}
/**
* Starts the HAL operation specific to the ClientMonitor subclass.
*/
protected abstract void startHalOperation();
protected final LazyDaemon<T> mLazyDaemon;
/**
* @param context system_server context
* @param lazyDaemon pointer for lazy retrieval of the HAL
* @param token a unique token for the client
* @param listener recipient of related events (e.g. authentication)
* @param userId target user id for operation
* @param owner name of the client that owns this
* @param cookie BiometricPrompt authentication cookie (to be moved into a subclass soon)
* @param sensorId ID of the sensor that the operation should be requested of
* @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants
*/
public HalClientMonitor(@NonNull Context context,
@NonNull LazyDaemon<T> lazyDaemon,@Nullable IBinder token,
@Nullable ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality,
int statsAction, int statsClient) {
super(context, token, listener, userId, owner, cookie, sensorId,
statsModality, statsAction, statsClient);
mLazyDaemon = lazyDaemon;
}
@Nullable
public T getFreshDaemon() {
return mLazyDaemon.getDaemon();
}
}
这里,实际上是跨进程调用远程对象BiometricsFingerprint.cpp下的方法enroll方法。
Return<RequestStatus> BiometricsFingerprint::enroll(
const hidl_array<uint8_t, 69>& hat, uint32_t gid, uint32_t timeoutSec) {
const hw_auth_token_t* authToken =
reinterpret_cast<const hw_auth_token_t*>(hat.data());
return ErrorFilter(mDevice->enroll(mDevice, authToken, gid, timeoutSec));
}
到这里,指纹录入流程,已经关联到指纹模组了,这里不再继续。
2.2 Android 12录入进度
我们接着前面分析,这里从下往上再来看,首先在BiometricsFingerprint里面
///hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
void BiometricsFingerprint::notify(const fingerprint_msg_t *msg) {
BiometricsFingerprint* thisPtr =
static_cast<BiometricsFingerprint*>(BiometricsFingerprint::getInstance());
std::lock_guard<std::mutex> lock(thisPtr->mClientCallbackMutex);
if (thisPtr == nullptr || thisPtr->mClientCallback == nullptr) {
ALOGE("Receiving callbacks before the client callback is registered.");
return;
}
const uint64_t devId = reinterpret_cast<uint64_t>(thisPtr->mDevice);
switch (msg->type) {
case FINGERPRINT_TEMPLATE_ENROLLING:
ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
msg->data.enroll.finger.fid,
msg->data.enroll.finger.gid,
msg->data.enroll.samples_remaining);
if (!thisPtr->mClientCallback->onEnrollResult(devId,
msg->data.enroll.finger.fid,
msg->data.enroll.finger.gid,
msg->data.enroll.samples_remaining).isOk()) {
ALOGE("failed to invoke fingerprint onEnrollResult callback");
}
break;
}
}
那么mClientCallback是怎么来的呢,在前面setNotify
Return<uint64_t> BiometricsFingerprint::setNotify(
const sp<IBiometricsFingerprintClientCallback>& clientCallback) {
std::lock_guard<std::mutex> lock(mClientCallbackMutex);
mClientCallback = clientCallback;
// This is here because HAL 2.1 doesn't have a way to propagate a
// unique token for its driver. Subsequent versions should send a unique
// token for each call to setNotify(). This is fine as long as there's only
// one fingerprint device on the platform.
return reinterpret_cast<uint64_t>(mDevice);
}
再来看clientCallback是什么时候赋值的,它是在Fingerprint21里面。
//frameworks/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
synchronized IBiometricsFingerprint getDaemon() {
if (mDaemon != null) {
return mDaemon;
}
try {
mDaemon = IBiometricsFingerprint.getService();
}
// HAL ID for these HIDL versions are only used to determine
// if callbacks have been successfully set.
long halId = 0;
try {
halId = mDaemon.setNotify(mHalResultController);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to set callback for fingerprint HAL", e);
mDaemon = null;
}
}
而mHalResultController是在 Fingerprint21的构造函数里面赋值的,
private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) {
...
fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor,
...
}
先看看 Fingerprint21.newInstance
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, BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps), gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(
sensorProps.sensorId,context, handler, scheduler);
return new Fingerprint21(context, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller);
}
原来是在这里创建的HalResultController。
public static class HalResultController extends IBiometricsFingerprintClientCallback.Stub {
@Override
public void onEnrollResult(long deviceId, int fingerId, int groupId,
int remaining) {
mHandler.post(() -> {
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (!(client instanceof FingerprintEnrollClient)) {
Slog.e(TAG, "onEnrollResult for non-enroll client: "
+ Utils.getClientName(client));
return;
}
final int currentUserId = client.getTargetUserId();
final CharSequence name = FingerprintUtils.getLegacyInstance(mSensorId)
.getUniqueName(mContext, currentUserId);
final Fingerprint fingerprint = new Fingerprint(
name, groupId, fingerId, deviceId);
final FingerprintEnrollClient enrollClient =
(FingerprintEnrollClient) client;
enrollClient.onEnrollResult(fingerprint, remaining);
});
}
}
HalResultController是Fingerprint21的静态内部类,内部实现了onEnrollResult
回到notify里面的!thisPtr->mClientCallback->onEnrollResult ,如此一来,就是调用HalResultController的onEnrollResult。
看最后的enrollClient.onEnrollResult(fingerprint, remaining);
先看看enrollClient是怎么来的。它是在HalResultController的构造函数传进来的,而scheduler是在Fingerprint21.newInstance中构造出来的, 它是一个BiometricScheduler对象。
///frameworks/base/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
/**
* @return the current operation
*/
public BaseClientMonitor getCurrentClient() {
if (mCurrentOperation == null) {
return null;
}
return mCurrentOperation.mClientMonitor;
}
而mCurrentOperation又是前面BiometricSchedulerstartNextOperationIfIdle
//frameworks/base/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
protected void startNextOperationIfIdle() {
mCurrentOperation = mPendingOperations.poll();
}
//
public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
@Nullable BaseClientMonitor.Callback clientCallback) {
startNextOperationIfIdle();
}
,上面的enrollClient是在前面的方法scheduleEnroll中传进来的,实际上就是FingerprintEnrollClient
继续追踪 FingerprintEnrollClient下的onEnrollResult 方法
@Override
public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
super.onEnrollResult(identifier, remaining);
mUdfpsHelper.onEnrollmentProgress(getSensorId(), remaining,
mUdfpsOverlayController);
if (remaining == 0) {
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
SidefpsHelper.hideOverlay(mSidefpsController);
}
}
先来看看录入指纹的进度条的逻辑controller.onEnrollmentProgress 。
public static void onEnrollmentProgress(int sensorId, int remaining,
@Nullable IUdfpsOverlayController udfpsOverlayController) {
if (udfpsOverlayController == null) {
return;
}
try {
udfpsOverlayController.onEnrollmentProgress(sensorId, remaining);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when sending onEnrollmentProgress", e);
}
}
这里的mUdfpsOverlayController是在FingerprintEnrollClient构造函数里面赋值的,而FingerprintEnrollClient初始化是在Fingerprint21#scheduleEnroll。
@Override
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
mUdfpsOverlayController = controller;
}
赋值是通过setUdfpsOverlayController,直接到了FingerprintService。
@Override
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
for (ServiceProvider provider : mServiceProviders) {
provider.setUdfpsOverlayController(controller);
}
}
继续往上到FingerprintManager。
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
if (mService == null) {
Slog.w(TAG, "setUdfpsOverlayController: no fingerprint service");
return;
}
try {
mService.setUdfpsOverlayController(controller);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
最终,发现设置的源头是SystemUI。
//frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
public UdfpsController(@NonNull Context context, ) {
mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
}
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
public void onEnrollmentProgress(int sensorId, int remaining) {
mFgExecutor.execute(() -> {
if (mServerRequest == null) {
Log.e(TAG, "onEnrollProgress received but serverRequest is null");
return;
}
mServerRequest.onEnrollmentProgress(remaining);
});
}
}
FingerprintEnrollClient下的onEnrollResult 方法继续看看FingerprintEnrollClient的父类。
///frameworks/base/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
if (mShouldVibrate) {
vibrateSuccess();
}
final ClientMonitorCallbackConverter listener = getListener();
try {
if (listener != null) {
listener.onEnrollResult(identifier, remaining);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
if (remaining == 0) {
mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(),
identifier);
logOnEnrolled(getTargetUserId(),
System.currentTimeMillis() - mEnrollmentStartTimeMs,
true /* enrollSuccessful */);
mCallback.onClientFinished(this, true /* success */);
}
notifyUserActivity();
}
///frameworks/base/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
throws RemoteException {
if (mFaceServiceReceiver != null) {
mFaceServiceReceiver.onEnrollResult((Face) identifier, remaining);
} else if (mFingerprintServiceReceiver != null) {
mFingerprintServiceReceiver.onEnrollResult(
(Fingerprint) identifier, remaining);
}
}
public ClientMonitorCallbackConverter(
IFingerprintServiceReceiver fingerprintServiceReceiver) {
mFingerprintServiceReceiver = fingerprintServiceReceiver;
}
看看ClientMonitorCallbackConverter构造的地方,在Fingerprint21。
@Override
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,{
final FingerprintEnrollClient client = new FingerprintEnrollClient(
mContext, mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController,
mSidefpsController, enrollReason);
}
这里直接到FingerprintService的enroll。然后到FingerprintManager#enroll
public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
EnrollmentCallback callback, @EnrollReason int enrollReason)
分析到这里,基本上结束,
3 指纹注册
3.1 指纹注册逻辑
在灭屏之后,PowerManagerService的Notifier线程会调用PhoneWindowManager#startedGoingToSleep通知startedGoingToSleep。
// Called on the PowerManager's Notifier thread.
@Override
public void startedGoingToSleep(int why) {
if (DEBUG_WAKEUP) {
Slog.i(TAG, "Started going to sleep... (why="
+ WindowManagerPolicyConstants.offReasonToString(why) + ")");
}
mGoingToSleep = true;
mRequestedOrGoingToSleep = true;
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(why);
}
}
调用KeyguardDelegate.onStartedGoingToSleep
方法,继而又会调用KeyguardServiceWrapper.java#onStartedGoingToSleep
方法,再调用KeyguardService#onStartedGoingToSleep
方法;并最终到达了KeyguardViewMediator#onStartedGoingToSleep
/**
* Called to let us know the screen was turned off.
* @param why either {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_USER} or
* {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}.
*/
public void onStartedGoingToSleep(int why) {
if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + why + ")");
...
mUpdateMonitor.dispatchStartedGoingToSleep(why);
notifyStartedGoingToSleep();
}
然后到KeyguardUpdateMonitor#dispatchStartedGoingToSleep
public void dispatchStartedGoingToSleep(int why) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, 0));
}
protected void handleStartedGoingToSleep(int arg1) {
Assert.isMainThread();
mLockIconPressed = false;
clearBiometricRecognized();
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onStartedGoingToSleep(arg1);
}
}
mGoingToSleep = true;
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_UPDATED_GOING_TO_SLEEP);
}
private void updateBiometricListeningState(int action,
@NonNull FaceAuthUiEvent faceAuthUiEvent) {
updateFingerprintListeningState(action);
updateFaceListeningState(action, faceAuthUiEvent);
}
private void updateFaceListeningState() {
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
return;
}
mHandler.removeCallbacks(mRetryFaceAuthentication);
boolean shouldListenForFace = shouldListenForFace();
if (mFaceRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFace) {
stopListeningForFace();
} else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING && shouldListenForFace) {
startListeningForFace();
}
}
private void updateFingerprintListeningState(int action) {
if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) {
setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
return;
}
final boolean shouldListenForFingerprint =
shouldListenForFingerprint(isUdfpsSupported());
final boolean runningOrRestarting =
mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
|| mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
if (runningOrRestarting && !shouldListenForFingerprint) {
if (action == BIOMETRIC_ACTION_START) {
mLogger.v("Ignoring stopListeningForFingerprint()");
return;
}
stopListeningForFingerprint();
} else if (!runningOrRestarting && shouldListenForFingerprint) {
if (action == BIOMETRIC_ACTION_STOP) {
mLogger.v("Ignoring startListeningForFingerprint()");
return;
}
startListeningForFingerprint();
}
}
private void startListeningForFingerprint() {
....
if (unlockPossible) {
mFingerprintCancelSignal = new CancellationSignal();
if (!isUnlockingWithFingerprintAllowed()) {
mLogger.v("startListeningForFingerprint - detect");
mFpm.detectFingerprint(
mFingerprintCancelSignal,
mFingerprintDetectionCallback,
new FingerprintAuthenticateOptions.Builder()
.setUserId(userId)
.build());
} else {
mLogger.v("startListeningForFingerprint");
mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal,
mFingerprintAuthenticationCallback,
null /* handler */,
new FingerprintAuthenticateOptions.Builder()
.setUserId(userId)
.build()
);
}
setFingerprintRunningState(BIOMETRIC_STATE_RUNNING);
}
}
这里先创建了一个CancellationSignal对象,这个类主要是给用户提供了一个cancel的接口来取消或者监听取消操作。mFpm变量就是FingerprintManager类对象实例,会调用指纹服务注册流程。
然后调用FingerprintManager#authenticate
来开始人脸解锁监听请求。
/**
* Version of authenticate with additional options.
* @hide
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, @NonNull Handler handler,
@NonNull FingerprintAuthenticateOptions options) {
if (mService != null) {
try {
useHandler(handler);
mAuthenticationCallback = callback;
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
final long authId = mService.authenticate(
mToken, operationId, mServiceReceiver, options);
if (cancel != null) {
cancel.setOnCancelListener(
new OnAuthenticationCancelListener(authId));
}
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
// Though this may not be a hardware issue,
// it will cause apps to give up or try again later.
callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */));
}
}
}
然后调用FingerprintService#authenticate
@Override // Binder call
public void 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);
}
这里首先调用canUseFingerprint进行权限校验,这个跟face是一样的,这里就不看了。
接着判断如果不是锁屏界面,就判断是不是生物认证,如果是生物认证就调用authenticateWithPrompt,否则就调动provider.second.scheduleAuthenticate。
这里我们看provider.second.scheduleAuthenticate,provider.second.scheduleAuthenticate在前面的时候介绍过,其实就是调用ServiceProvider#scheduleAuthenticate,而Fingerprint21实现了ServiceProvider。
public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
因此,我们直接看Fingerprint21#scheduleAuthenticate
@Override
public void scheduleAuthenticate(@NonNull IBinder token, long operationId,
int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull FingerprintAuthenticateOptions options,
long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(options.getUserId());
final boolean isStrongBiometric =
Utils.isStrongBiometric(mSensorProperties.sensorId);
final FingerprintAuthenticationClient client =
new FingerprintAuthenticationClient(
mContext, mLazyDaemon, token, requestId, listener, operationId,
restricted, options, cookie, false /* requireConfirmation */,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
});
}
这里说明一下,mScheduler是在这里定义的
@NonNull
private List<ServiceProvider> getHidlProviders(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
final List<ServiceProvider> providers = new ArrayList<>();
for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) {
final Fingerprint21 fingerprint21;
...
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(),
mBiometricStateCallback, hidlSensor, mHandler,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
providers.add(fingerprint21);
}
return providers;
}
public static Fingerprint21 newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
final BiometricScheduler scheduler = new BiometricScheduler(TAG,
BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps),
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(
sensorProps.sensorId, context, handler, scheduler);
return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler,
handler,lockoutResetDispatcher, controller,
BiometricContext.getInstance(context));
}
继续往下看,类BiometricScheduler的scheduleClientMonitor
/**
* Adds a {@link BaseClientMonitor} to the pending queue
*
* @param clientMonitor operation to be scheduled
* @param clientCallback optional callback, invoked when the client state changes.
*/
public void scheduleClientMonitor(@NonNull BaseClientMonitor clientMonitor,
@Nullable ClientMonitorCallback clientCallback) {
// If the incoming operation should interrupt preceding clients,
// mark any interruptable pending clients as canceling.
// Once they reach the head of the queue,
// the scheduler will send ERROR_CANCELED and skip the operation.
if (clientMonitor.interruptsPrecedingClients()) {
for (BiometricSchedulerOperation operation : mPendingOperations) {
if (operation.markCanceling()) {
Slog.d(getTag(), "New client, marking pending op as canceling: "
+ operation);
}
}
}
mPendingOperations.add(
new BiometricSchedulerOperation(clientMonitor, clientCallback));
Slog.d(getTag(), "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());
// If the new operation should interrupt preceding clients,
// and if the current operation is cancellable, start the cancellation process.
if (clientMonitor.interruptsPrecedingClients()
&& mCurrentOperation != null
&& mCurrentOperation.isInterruptable()
&& mCurrentOperation.isStarted()) {
Slog.d(getTag(), "[Cancelling Interruptable]: " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
} else {
startNextOperationIfIdle();
}
}
然后来到方法startNextOperationIfIdle
protected void startNextOperationIfIdle() {
...
mCurrentOperation = mPendingOperations.poll();
Slog.d(getTag(), "[Polled] " + mCurrentOperation);
...
if (mGestureAvailabilityDispatcher != null
&& mCurrentOperation.isAcquisitionOperation()) {
mGestureAvailabilityDispatcher.markSensorActive(
mCurrentOperation.getSensorId(), true /* active */);
}
// Not all operations start immediately. BiometricPrompt waits for its operation
// to arrive at the head of the queue, before pinging it to start.
final int cookie = mCurrentOperation.isReadyToStart(mInternalCallback);
if (cookie == 0) {
if (!mCurrentOperation.start(mInternalCallback)) {
// Note down current length of queue
final int pendingOperationsLength = mPendingOperations.size();
final BiometricSchedulerOperation lastOperation =
mPendingOperations.peekLast();
Slog.e(getTag(), "[Unable To Start] " + mCurrentOperation
+ ". Last pending operation: " + lastOperation);
// Then for each operation currently in the pending queue
// at the time of this failure, do the same as above. Otherwise,
// it's possible that something like setActiveUser fails,
// but then authenticate (for the wrong user) is invoked.
for (int i = 0; i < pendingOperationsLength; i++) {
final BiometricSchedulerOperation operation =
mPendingOperations.pollFirst();
if (operation != null) {
Slog.w(getTag(), "[Aborting Operation] " + operation);
operation.abort();
} else {
Slog.e(getTag(), "Null operation, index: " + i
+ ", expected length: " + pendingOperationsLength);
}
}
// It's possible that during cleanup a new set of operations came in.
// We can try to run these. A single request from the manager layer
// to the service layer may actually be multiple operations
// (i.e. updateActiveUser + authenticate).
mCurrentOperation = null;
startNextOperationIfIdle();
}
} else {
try {
mBiometricService.onReadyForAuthentication(
mCurrentOperation.getClientMonitor().getRequestId(), cookie);
} catch (RemoteException e) {
Slog.e(getTag(), "Remote exception when contacting BiometricService", e);
}
Slog.d(getTag(), "Waiting for cookie before starting: " + mCurrentOperation);
}
}
mCurrentOperation.start(mInternalCallback),这里要分析变量currentClient,它是从前面startNextOperationIfIdle拿到的。
mCurrentOperation = mPendingOperations.poll();
而又是从前面BiometricScheduler#scheduleClientMonitor从添加的
mPendingOperations.add(new BiometricSchedulerOperation(clientMonitor, clientCallback));
Slog.d(getTag(), "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());
这里是创建了一个BiometricSchedulerOperation对象,来保存clientMonitor
BiometricSchedulerOperation(@NonNull BaseClientMonitor clientMonitor,
@Nullable ClientMonitorCallback callback) {
this(clientMonitor, callback, STATE_WAITING_IN_QUEUE);
}
因此上面的mCurrentOperation.start实际上是调用的BiometricSchedulerOperation的start。
/**
* Start this operation without waiting for a cookie
* (i.e. {@link #isReadyToStart(ClientMonitorCallback)} returns zero}
*
* @param callback lifecycle callback
* @return if this operation started
*/
public boolean start(@NonNull ClientMonitorCallback callback) {
if (errorWhenNoneOf("start",
STATE_WAITING_IN_QUEUE,
STATE_WAITING_FOR_COOKIE,
STATE_WAITING_IN_QUEUE_CANCELING)) {
return false;
}
if (mClientMonitor.getCookie() != 0) {
String err = "operation requires cookie";
if (mIsDebuggable.getAsBoolean()) {
throw new IllegalStateException(err);
}
Slog.e(TAG, err);
}
return doStart(callback);
}
private boolean doStart(@NonNull ClientMonitorCallback callback) {
mOnStartCallback = callback;
final ClientMonitorCallback cb = getWrappedCallback(callback);
if (mState == STATE_WAITING_IN_QUEUE_CANCELING) {
Slog.d(TAG, "Operation marked for cancellation, cancelling now: " + this);
cb.onClientFinished(mClientMonitor, true /* success */);
if (mClientMonitor instanceof ErrorConsumer) {
final ErrorConsumer errorConsumer = (ErrorConsumer) mClientMonitor;
errorConsumer.onError(BiometricConstants.BIOMETRIC_ERROR_CANCELED,
0 /* vendorCode */);
} else {
Slog.w(TAG, "monitor cancelled but does not implement ErrorConsumer");
}
return false;
}
if (isUnstartableHalOperation()) {
Slog.v(TAG, "unable to start: " + this);
((HalClientMonitor<?>) mClientMonitor).unableToStart();
cb.onClientFinished(mClientMonitor, false /* success */);
return false;
}
mState = STATE_STARTED;
mClientMonitor.start(cb);
Slog.v(TAG, "started: " + this);
return true;
}
最后还是调用了mClientMonitor.start(cb);,这个mClientMonitor正是从BiometricSchedulerOperation的构造函数赋值的。而mClientMonitor我们知道,它是在前面Fingerprint21#scheduleAuthenticate中创建的。
final FingerprintAuthenticationClient client =
new FingerprintAuthenticationClient(
mContext, mLazyDaemon, token, requestId, listener, operationId,
restricted, options, cookie, false /* requireConfirmation */,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
以前,我们直接看FingerprintAuthenticationClient的start方法。
@Override
public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
if (mSensorProps.isAnyUdfpsType()) {
// UDFPS requires user to touch before becoming "active"
mState = STATE_STARTED_PAUSED;
} else {
mState = STATE_STARTED;
}
}
这里只是赋值状态为STATE_STARTED,我们直接看父类的super.start,这里是AuthenticationClient 类下的start方法。
/**
* Start authentication
*/
@Override
public void start(@NonNull ClientMonitorCallback callback) {
super.start(callback);
final @LockoutTracker.LockoutMode int lockoutMode;
if (mShouldUseLockoutTracker) {
lockoutMode = mLockoutTracker.getLockoutModeForUser(getTargetUserId());
} else {
lockoutMode = getBiometricContext().getAuthSessionCoordinator()
.getLockoutStateFor(getTargetUserId(), mSensorStrength);
}
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
Slog.v(TAG, "In lockout mode(" + lockoutMode
+ ") ; disallowing authentication");
int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED
? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
: BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
onError(errorCode, 0 /* vendorCode */);
return;
}
if (mTaskStackListener != null) {
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
}
Slog.d(TAG, "Requesting auth for " + getOwnerString());
mStartTimeMs = System.currentTimeMillis();
mAuthAttempted = true;
startHalOperation();
}
很明显,这里是startHalOperation(),实际上就是调用到FingerprintAuthenticationClient 类下的startHalOperation。
@Override
protected void startHalOperation() {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
.isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
return;
}
try {
getFreshDaemon().authenticate(mOperationId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
}
}
getFreshDaemon().authenticate 就是进行指纹服务注册,后面会继续分析相关底层。
@VisibleForTesting
synchronized IBiometricsFingerprint getDaemon() {
if (mTestHalEnabled) {
final TestHal testHal = new TestHal(mContext, mSensorId);
testHal.setNotify(mHalResultController);
return testHal;
}
if (mDaemon != null) {
return mDaemon;
}
Slog.d(TAG, "Daemon was null, reconnecting, current operation: "
+ mScheduler.getCurrentClient());
try {
mDaemon = IBiometricsFingerprint.getService();
} catch (java.util.NoSuchElementException e) {
// Service doesn't exist or cannot be opened.
Slog.w(TAG, "NoSuchElementException", e);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get fingerprint HAL", e);
}
if (mDaemon == null) {
Slog.w(TAG, "Fingerprint HAL not available");
return null;
}
mDaemon.asBinder().linkToDeath(this, 0 /* flags */);
// HAL ID for these HIDL versions are only used to determine if callbacks have been
// successfully set.
long halId = 0;
try {
halId = mDaemon.setNotify(mHalResultController);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to set callback for fingerprint HAL", e);
mDaemon = null;
}
Slog.d(TAG, "Fingerprint HAL ready, HAL ID: " + halId);
if (halId != 0) {
scheduleLoadAuthenticatorIds();
scheduleInternalCleanup(ActivityManager.getCurrentUser(), null /* callback */);
} else {
Slog.e(TAG, "Unable to set callback");
mDaemon = null;
}
return mDaemon;
}
mDaemon 是通过mDaemon = IBiometricsFingerprint.getService();拿到的,前面说过,它是跨进程调用远程对象BiometricsFingerprint.cpp。
我们来看BiometricsFingerprint
//hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
Return<RequestStatus> BiometricsFingerprint::authenticate(uint64_t operationId,
uint32_t gid) {
return ErrorFilter(mDevice->authenticate(mDevice, operationId, gid));
}
这里mDevice是在BiometricsFingerprint构造里面初始化的。
BiometricsFingerprint::BiometricsFingerprint() : mClientCallback(nullptr), mDevice(nullptr) {
sInstance = this; // keep track of the most recent instance
mDevice = openHal();
if (!mDevice) {
ALOGE("Can't open HAL module");
}
}
再来看openHal方法
fingerprint_device_t* BiometricsFingerprint::openHal() {
int err;
const hw_module_t *hw_mdl = nullptr;
ALOGD("Opening fingerprint hal library...");
if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_mdl))) {
ALOGE("Can't open fingerprint HW Module, error: %d", err);
return nullptr;
}
if (hw_mdl == nullptr) {
ALOGE("No valid fingerprint module");
return nullptr;
}
fingerprint_module_t const *module =
reinterpret_cast<const fingerprint_module_t*>(hw_mdl);
if (module->common.methods->open == nullptr) {
ALOGE("No valid open method");
return nullptr;
}
hw_device_t *device = nullptr;
if (0 != (err = module->common.methods->open(hw_mdl, nullptr, &device))) {
ALOGE("Can't open fingerprint methods, error: %d", err);
return nullptr;
}
if (kVersion != device->version) {
// enforce version on new devices because of HIDL@2.1 translation layer
ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
return nullptr;
}
fingerprint_device_t* fp_device =
reinterpret_cast<fingerprint_device_t*>(device);
if (0 != (err =
fp_device->set_notify(fp_device, BiometricsFingerprint::notify))) {
ALOGE("Can't register fingerprint module callback, error: %d", err);
return nullptr;
}
return fp_device;
}
这个方法最终会访问到底层了,比如我们熟悉的hw_get_module。设置回调到底软 ,后面有设置
dev->set_notify = set_notify_callback;
我们来看module->common.methods->open
这个open方法主要是将厂商指纹模组模块的算法识别逻辑结果和HAL层进行绑定(一般是fingerprint.default.so文件),设置回调通知,这个文件一般都不开源,不过Android原生也是有这部分代码的(当然只是看看,并不能使用)
我们来看hardware/libhardware/modules/fingerprint/fingerprint.c
static int fingerprint_open(const hw_module_t* module, const char __unused *id,
hw_device_t** device)
{
if (device == NULL) {
ALOGE("NULL device on open");
return -EINVAL;
}
fingerprint_device_t *dev = malloc(sizeof(fingerprint_device_t));
memset(dev, 0, sizeof(fingerprint_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = FINGERPRINT_MODULE_API_VERSION_2_0;
dev->common.module = (struct hw_module_t*) module;
dev->common.close = fingerprint_close;
dev->pre_enroll = fingerprint_pre_enroll;
dev->enroll = fingerprint_enroll;
dev->get_authenticator_id = fingerprint_get_auth_id;
dev->cancel = fingerprint_cancel;
dev->remove = fingerprint_remove;
dev->set_active_group = fingerprint_set_active_group;
dev->authenticate = fingerprint_authenticate;
dev->set_notify = set_notify_callback;
dev->notify = NULL;
*device = (hw_device_t*) dev;
return 0;
}
static struct hw_module_methods_t fingerprint_module_methods = {
.open = fingerprint_open,
};
fingerprint_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = FINGERPRINT_HARDWARE_MODULE_ID,
.name = "Demo Fingerprint HAL",
.author = "The Android Open Source Project",
.methods = &fingerprint_module_methods,
},
};
好了,后面authenticate的逻辑,我们没有代码就不分析了,指纹服务注册分析到此为止。
3.2 总结
4 指纹解锁
4.1 指纹认证成功回调的传递
当指纹注册完,用户进行指纹认证成功后,底层库返回结果后会调用onAuthenticated来反馈结果给receiver,在往上层反馈。
我们从BiometricsFingerprint开始分析
void BiometricsFingerprint::notify(const fingerprint_msg_t *msg) {
BiometricsFingerprint* thisPtr = static_cast<BiometricsFingerprint*>(
BiometricsFingerprint::getInstance());
std::lock_guard<std::mutex> lock(thisPtr->mClientCallbackMutex);
if (thisPtr == nullptr || thisPtr->mClientCallback == nullptr) {
ALOGE("Receiving callbacks before the client callback is registered.");
return;
}
const uint64_t devId = reinterpret_cast<uint64_t>(thisPtr->mDevice);
switch (msg->type) {
case FINGERPRINT_ERROR: {
int32_t vendorCode = 0;
FingerprintError result = VendorErrorFilter(msg->data.error, &vendorCode);
ALOGD("onError(%d)", result);
if (!thisPtr->mClientCallback->onError(devId, result, vendorCode).isOk()) {
ALOGE("failed to invoke fingerprint onError callback");
}
}
break;
case FINGERPRINT_ACQUIRED: {
int32_t vendorCode = 0;
FingerprintAcquiredInfo result =
VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode);
ALOGD("onAcquired(%d)", result);
if (!thisPtr->mClientCallback->onAcquired(devId, result, vendorCode).isOk()) {
ALOGE("failed to invoke fingerprint onAcquired callback");
}
}
break;
case FINGERPRINT_TEMPLATE_ENROLLING:
ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
msg->data.enroll.finger.fid,
msg->data.enroll.finger.gid,
msg->data.enroll.samples_remaining);
if (!thisPtr->mClientCallback->onEnrollResult(devId,
msg->data.enroll.finger.fid,
msg->data.enroll.finger.gid,
msg->data.enroll.samples_remaining).isOk()) {
ALOGE("failed to invoke fingerprint onEnrollResult callback");
}
break;
case FINGERPRINT_TEMPLATE_REMOVED:
ALOGD("onRemove(fid=%d, gid=%d, rem=%d)",
msg->data.removed.finger.fid,
msg->data.removed.finger.gid,
msg->data.removed.remaining_templates);
if (!thisPtr->mClientCallback->onRemoved(devId,
msg->data.removed.finger.fid,
msg->data.removed.finger.gid,
msg->data.removed.remaining_templates).isOk()) {
ALOGE("failed to invoke fingerprint onRemoved callback");
}
break;
case FINGERPRINT_AUTHENTICATED:
if (msg->data.authenticated.finger.fid != 0) {
ALOGD("onAuthenticated(fid=%d, gid=%d)",
msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid);
const uint8_t* hat =
reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
const hidl_vec<uint8_t> token(
std::vector<uint8_t>(hat, hat + sizeof(msg->data.authenticated.hat)));
if (!thisPtr->mClientCallback->onAuthenticated(devId,
msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid,
token).isOk()) {
ALOGE("failed to invoke fingerprint onAuthenticated callback");
}
} else {
// Not a recognized fingerprint
if (!thisPtr->mClientCallback->onAuthenticated(devId,
msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid,
hidl_vec<uint8_t>()).isOk()) {
ALOGE("failed to invoke fingerprint onAuthenticated callback");
}
}
break;
case FINGERPRINT_TEMPLATE_ENUMERATING:
ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
msg->data.enumerated.finger.fid,
msg->data.enumerated.finger.gid,
msg->data.enumerated.remaining_templates);
if (!thisPtr->mClientCallback->onEnumerate(devId,
msg->data.enumerated.finger.fid,
msg->data.enumerated.finger.gid,
msg->data.enumerated.remaining_templates).isOk()) {
ALOGE("failed to invoke fingerprint onEnumerate callback");
}
break;
}
我们直接看FINGERPRINT_AUTHENTICATED分支。
这里关键是
thisPtr->mClientCallback->onAuthenticated(devId,
msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid,
token).isOk())
thisPtr就是BiometricsFingerprint,mClientCallback赋值的地方是在setNotify
//hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
Return<uint64_t> BiometricsFingerprint::setNotify(
const sp<IBiometricsFingerprintClientCallback>& clientCallback) {
std::lock_guard<std::mutex> lock(mClientCallbackMutex);
mClientCallback = clientCallback;
// This is here because HAL 2.1 doesn't have a way to propagate a
// unique token for its driver. Subsequent versions should send a unique
// token for each call to setNotify(). This is fine as long as there's only
// one fingerprint device on the platform.
return reinterpret_cast<uint64_t>(mDevice);
}
clientCallback是一个IBiometricsFingerprintClientCallback对象,先看看IBiometricsFingerprintClientCallback的实现。
//framework/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
public static class HalResultController extends IBiometricsFingerprintClientCallback.Stub {
}
IBiometricsFingerprintClientCallback的实现类是HalResultController。
再来看HalResultController是如何创建的。
public static Fingerprint21 newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
final BiometricScheduler scheduler = new BiometricScheduler(
TAG, BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps),
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(
sensorProps.sensorId, context, handler, scheduler);
return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler,
handler, lockoutResetDispatcher, controller,
BiometricContext.getInstance(context));
}
它的创建是在Fingerprint21#newInstance中,然后传递给了Fingerprint21。
mHalResultController = controller;
在Fingerprint21的构造函数也就是把它赋值给mHalResultController。
那么我们来看看mHalResultController是怎么和hardware层联系起来的。
synchronized IBiometricsFingerprint getDaemon() {
// HAL ID for these HIDL versions are only used to determine
// if callbacks have been successfully set.
long halId = 0;
try {
halId = mDaemon.setNotify(mHalResultController);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to set callback for fingerprint HAL", e);
mDaemon = null;
}
}
@Nullable private IBiometricsFingerprint mDaemon;
答案是在getDaemon()里面,通过上节我们知道,这里mDaemon就是BiometricsFingerprint,这就调用到了BiometricsFingerprint#setNotify。
public static class HalResultController extends IBiometricsFingerprintClientCallback.Stub {
@Override
public void onAuthenticated(long deviceId, int fingerId, int groupId,
ArrayList<Byte> token) {
mHandler.post(() -> {
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (!(client instanceof AuthenticationConsumer)) {
Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
+ Utils.getClientName(client));
return;
}
final AuthenticationConsumer authenticationConsumer =
(AuthenticationConsumer) client;
final boolean authenticated = fingerId != 0;
final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
authenticationConsumer.onAuthenticated(fp, authenticated, token);
});
}
}
所以,mClientCallback->onAuthenticated实际调用的是HalResultController#onAuthenticated。
而HalResultController#onAuthenticated会从mScheduler.getCurrentClient()中拿到client,然后转化为AuthenticationConsumer对象,调用它的onAuthenticated。
首先mScheduler前面其实分析过,它的创建是在Fingerprint21#newInstance。
/**
* Get current operation <code>BaseClientMonitor</code>
* @deprecated TODO: b/229994966, encapsulate client monitors
* @return the current operation
*/
@Deprecated
@Nullable
public BaseClientMonitor getCurrentClient() {
return mCurrentOperation != null ? mCurrentOperation.getClientMonitor() : null;
}
这里getCurrentClient()最终拿到的是FingerprintAuthenticationClient。
@Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
super.onAuthenticated(identifier, authenticated, token);
// Authentication lifecycle ends either when
// 1) Authenticated == true
// 2) Error occurred (lockout or some other error)
// Note that authentication doesn't end when Authenticated == false
if (authenticated) {
mState = STATE_STOPPED;
resetFailedAttempts(getTargetUserId());
mSensorOverlays.hide(getSensorId());
} else {
mState = STATE_STARTED_PAUSED_ATTEMPTED;
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
Slog.w(TAG, "Fingerprint locked out, lockoutMode(" + lockoutMode + ")");
final int errorCode = lockoutMode == LockoutTracker.LOCKOUT_TIMED
? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
: BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
// Send the error, but do not invoke the FinishCallback yet. Since lockout is not
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
mSensorOverlays.hide(getSensorId());
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
}
}
这里将mState 设置为STATE_STOPPED,继续看它的父类AuthenticationClient#onAuthenticated。
//framework/base/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
super.logOnAuthenticated(getContext(), authenticated, mRequireConfirmation,
getTargetUserId(), isBiometricPrompt());
final BiometricServiceBase.ServiceListener listener = getListener();
mMetricsLogger.action(mConstants.actionBiometricAuth(), authenticated);
boolean result = false;
try {
if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + authenticated + ")"
+ ", ID:" + identifier.getBiometricId()
+ ", Owner: " + getOwnerString()
+ ", isBP: " + isBiometricPrompt()
+ ", listener: " + listener
+ ", requireConfirmation: " + mRequireConfirmation
+ ", user: " + getTargetUserId());
// Ensure authentication only succeeds if the client activity is on top or is keyguard.
boolean isBackgroundAuth = false;
if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) {
try {
final List<ActivityManager.RunningTaskInfo> tasks =
ActivityTaskManager.getService().getTasks(1);
if (tasks == null || tasks.isEmpty()) {
Slog.e(TAG, "No running tasks reported");
isBackgroundAuth = true;
} else {
final ComponentName topActivity = tasks.get(0).topActivity;
if (topActivity == null) {
Slog.e(TAG, "Unable to get top activity");
isBackgroundAuth = true;
} else {
final String topPackage = topActivity.getPackageName();
if (!topPackage.contentEquals(getOwnerString())) {
Slog.e(TAG, "Background authentication detected, top: " + topPackage
+ ", client: " + this);
isBackgroundAuth = true;
}
}
}
} catch (RemoteException e) {
Slog.e(TAG, "Unable to get running tasks", e);
isBackgroundAuth = true;
}
}
// Fail authentication if we can't confirm the client activity is on top.
if (isBackgroundAuth) {
Slog.e(TAG, "Failing possible background authentication");
authenticated = false;
// SafetyNet logging for exploitation attempts of b/159249069.
final ApplicationInfo appInfo = getContext().getApplicationInfo();
EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1,
"Attempted background authentication");
}
if (authenticated) {
// SafetyNet logging for b/159249069 if constraint is violated.
if (isBackgroundAuth) {
final ApplicationInfo appInfo = getContext().getApplicationInfo();
EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1,
"Successful background authentication!");
}
mAlreadyDone = true;
if (listener != null) {
vibrateSuccess();
}
result = true;
if (shouldFrameworkHandleLockout()) {
resetFailedAttempts();
}
onStop();
final byte[] byteToken = new byte[token.size()];
for (int i = 0; i < token.size(); i++) {
byteToken[i] = token.get(i);
}
if (isBiometricPrompt() && listener != null) {
// BiometricService will add the token to keystore
listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken,
isStrongBiometric());
} else if (!isBiometricPrompt() && listener != null) {
if (isStrongBiometric()) {
KeyStore.getInstance().addAuthToken(byteToken);
} else {
Slog.d(getLogTag(), "Skipping addAuthToken");
}
try {
// Explicitly have if/else here to make it super obvious in case the code is
// touched in the future.
if (!getIsRestricted()) {
listener.onAuthenticationSucceeded(
getHalDeviceId(), identifier, getTargetUserId());
} else {
listener.onAuthenticationSucceeded(
getHalDeviceId(), null, getTargetUserId());
}
} catch (RemoteException e) {
Slog.e(getLogTag(), "Remote exception", e);
}
} else {
// Client not listening
Slog.w(getLogTag(), "Client not listening");
result = true;
}
} else {
if (listener != null) {
vibrateError();
}
// Allow system-defined limit of number of attempts before giving up
final int lockoutMode = handleFailedAttempt();
if (lockoutMode != LOCKOUT_NONE && shouldFrameworkHandleLockout()) {
Slog.w(getLogTag(), "Forcing lockout (driver code should do this!), mode("
+ lockoutMode + ")");
stop(false);
final int errorCode = lockoutMode == LOCKOUT_TIMED
? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
: BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
} else {
// Don't send onAuthenticationFailed if we're in lockout, it causes a
// janky UI on Keyguard/BiometricPrompt since "authentication failed"
// will show briefly and be replaced by "device locked out" message.
if (listener != null) {
if (isBiometricPrompt()) {
listener.onAuthenticationFailedInternal();
} else {
listener.onAuthenticationFailed(getHalDeviceId());
}
}
}
result = lockoutMode != LOCKOUT_NONE; // in a lockout mode
if(result) { // locked out
mAlreadyDone = true;
}
}
} catch (RemoteException e) {
Slog.e(getLogTag(), "Remote exception", e);
result = true;
}
return result;
}
如果认证结果返回但是当前不是锁屏界面,并且判断是isBackgroundAuth的时候,就会将认证解锁authenticated设置为false,这时会进行认错误震动,如果是BiometricPrompt,就回调onAuthenticationFailedInternal,否则回调onAuthenticationFailed。
如果authenticated设置为true,会进行认证成功震动,并且重置错误次数resetFailedAttempts,如果是BiometricPrompt就回调onAuthenticationSucceededInternal,否则如果是isStrongBiometric,会向KeyStore中加入认证成功的记录byteToken,最后回调onAuthenticationSucceeded。
再来看listener
final ClientMonitorCallbackConverter listener = getListener();
我们从ClientMonitorCallbackConverter的构造函数开始。
public ClientMonitorCallbackConverter(IFingerprintServiceReceiver fingerprintServiceReceiver) {
mFingerprintServiceReceiver = fingerprintServiceReceiver;
}
它的创建是在FingerprintService
//framework/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@Override // Binder call
public long authenticate(
final IBinder token,
final long operationId,
final IFingerprintServiceReceiver receiver,
final FingerprintAuthenticateOptions options) {
...
return provider.second.scheduleAuthenticate(token, operationId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), options,
restricted, statsClient, isKeyguard);
}
继续看Fingerprint21#scheduleAuthenticate
//framework/base/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
mContext, mLazyDaemon, token, requestId, listener, operationId,
restricted, options, cookie, false /* requireConfirmation */,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
再来看FingerprintAuthenticationClient的构造函数。
FingerprintAuthenticationClient(@NonNull Context context,
@NonNull Supplier<IBiometricsFingerprint> lazyDaemon,
@NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, long operationId,
boolean restricted, @NonNull FingerprintAuthenticateOptions options,
int cookie, boolean requireConfirmation, @NonNull BiometricLogger logger,
@NonNull BiometricContext biometricContext, boolean isStrongBiometric,
@NonNull TaskStackListener taskStackListener,
@NonNull LockoutFrameworkImpl lockoutTracker,
@Nullable IUdfpsOverlayController udfpsOverlayController,
@Nullable ISidefpsController sidefpsController,
@Nullable IUdfpsOverlay udfpsOverlay,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Authenticators.Types int sensorStrength) {
super(context, lazyDaemon, token, listener, operationId, restricted,
options, cookie, requireConfirmation, logger, biometricContext,
isStrongBiometric, taskStackListener, lockoutTracker,
allowBackgroundAuthentication, false /* shouldVibrate */,
sensorStrength);
继续看父类
//framework/base/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
public AuthenticationClient(@NonNull Context context,
@NonNull Supplier<T> lazyDaemon,
@NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener,
long operationId, boolean restricted, @NonNull O options,
int cookie, boolean requireConfirmation,
@NonNull BiometricLogger biometricLogger,
@NonNull BiometricContext biometricContext,
boolean isStrongBiometric,
@Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker,
boolean allowBackgroundAuthentication,
boolean shouldVibrate, int sensorStrength) {
super(context, lazyDaemon, token, listener, options.getUserId(),
options.getOpPackageName(), cookie, options.getSensorId(), shouldVibrate,
biometricLogger, biometricContext);
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
mRequireConfirmation = requireConfirmation;
mActivityTaskManager = getActivityTaskManager();
mBiometricManager = context.getSystemService(BiometricManager.class);
mTaskStackListener = taskStackListener;
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
mAllowBackgroundAuthentication = allowBackgroundAuthentication;
mShouldUseLockoutTracker = lockoutTracker != null;
mSensorStrength = sensorStrength;
mOptions = options;
}
继续看父类
//framework/base/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
public AcquisitionClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
@NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener,
int userId,
@NonNull String owner, int cookie, int sensorId,
boolean shouldVibrate,
@NonNull BiometricLogger logger,
@NonNull BiometricContext biometricContext) {
super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId,
logger, biometricContext);
mPowerManager = context.getSystemService(PowerManager.class);
mShouldVibrate = shouldVibrate;
}
继续看父类
//framework/base/services/core/java/com/android/server/biometrics/sensors/HalClientMonitor.java
public HalClientMonitor(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
@Nullable IBinder token,
@Nullable ClientMonitorCallbackConverter listener,
int userId,
@NonNull String owner, int cookie, int sensorId,
@NonNull BiometricLogger biometricLogger,
@NonNull BiometricContext biometricContext) {
super(context, token, listener, userId, owner, cookie, sensorId,
biometricLogger, biometricContext);
mLazyDaemon = lazyDaemon;
mOperationContext = new OperationContextExt(isBiometricPrompt());
}
继续看父类
//framework/base/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
/**
* @param context system_server context
* @param token a unique token for the client
* @param listener recipient of related events (e.g. authentication)
* @param userId target user id for operation
* @param owner name of the client that owns this
* @param cookie BiometricPrompt authentication cookie (to be moved into a subclass soon)
* @param sensorId ID of the sensor that the operation should be requested of
* @param logger framework stats logger
* @param biometricContext system context metadata
*/
public BaseClientMonitor(@NonNull Context context,
@Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) {
mSequentialId = sCount++;
mContext = context;
mToken = token;
mRequestId = -1;
mListener = listener;
mTargetUserId = userId;
mOwner = owner;
mCookie = cookie;
mSensorId = sensorId;
mLogger = logger;
mBiometricContext = biometricContext;
try {
if (token != null) {
token.linkToDeath(this, 0);
}
} catch (RemoteException e) {
Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
}
}
@Nullable
public final ClientMonitorCallbackConverter getListener() {
return mListener;
}
终于不用看父类了!!!
这里没有回调mListener,而是提供了一个getListener(),看来是给子类用的。
到这里,我们知道 listener.onAuthenticationSucceeded(getHalDeviceId(), null, getTargetUserId());调用的是ClientMonitorCallbackConverter的onAuthenticationSucceeded
//framework/base/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
void onAuthenticationSucceeded(int sensorId, BiometricAuthenticator.Identifier identifier,
byte[] token, int userId, boolean isStrongBiometric) throws RemoteException {
if (mSensorReceiver != null) {
mSensorReceiver.onAuthenticationSucceeded(sensorId, token);
} else if (mFaceServiceReceiver != null) {
mFaceServiceReceiver.onAuthenticationSucceeded((Face) identifier, userId,
isStrongBiometric);
} else if (mFingerprintServiceReceiver != null) {
mFingerprintServiceReceiver.onAuthenticationSucceeded((Fingerprint) identifier, userId,
isStrongBiometric);
}
}
public ClientMonitorCallbackConverter(IFingerprintServiceReceiver fingerprintServiceReceiver) {
mFingerprintServiceReceiver = fingerprintServiceReceiver;
}
而mFingerprintServiceReceiver是从FingerprintService赋值并转换的。
@Override // Binder call
public long authenticate() {
...
return provider.second.scheduleAuthenticate(token, operationId,
0 /* cookie */, new ClientMonitorCallbackConverter(receiver), options,
restricted, statsClient, isKeyguard);
}
继续看FingerprintManager的authenticate
final long authId = mService.authenticate(mToken, operationId, mServiceReceiver, options);
在FingerprintManager里面将mAuthenticationCallback存起来,并将mServiceReceiver传递给FingerprintService。
//framework/base/core/java/android/hardware/fingerprint/FingerprintManager.java
private IFingerprintServiceReceiver mServiceReceiver =
new IFingerprintServiceReceiver.Stub() {
@Override // binder call
public void onAuthenticationSucceeded(Fingerprint fp, int userId,
boolean isStrongBiometric) {
mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId,
isStrongBiometric ? 1 : 0,fp).sendToTarget();
}
}
private class MyHandler extends Handler {
@Override
public void handleMessage(android.os.Message msg) {
case MSG_AUTHENTICATION_SUCCEEDED:
sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */,
msg.arg2 == 1 /* isStrongBiometric */);
break;
}
}
private void sendAuthenticatedSucceeded(Fingerprint fp, int userId,
boolean isStrongBiometric) {
if (mAuthenticationCallback != null) {
final AuthenticationResult result =
new AuthenticationResult(mCryptoObject, fp, userId, isStrongBiometric);
mAuthenticationCallback.onAuthenticationSucceeded(result);
}
}
这里mAuthenticationCallback是在FingerprintManager#authenticate中赋值的。
到这里,FingerprintManager将onAuthenticationSucceeded的消息传递到了SystemUI,开始后面的解锁流程。
4.2 指纹解锁
因此,再来看SystemUI的KeyguardUpdateMonitor中指纹注册时传递的回调的mFingerprintAuthenticationCallback。
final FingerprintManager.AuthenticationCallback mFingerprintAuthenticationCallback
= new AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
handleFingerprintAuthenticated(result.getUserId(),
result.isStrongBiometric());
Trace.endSection();
}
};
调用handleFingerprintAuthenticated
private void handleFingerprintAuthenticated(int authUserId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#handlerFingerPrintAuthenticated");
if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
mLogger.d("handleFingerprintAuthenticated()"
+ " triggered while waiting for cancellation, removing watchdog");
mHandler.removeCallbacks(mFpCancelNotReceived);
}
try {
final int userId = mUserTracker.getUserId();
if (userId != authUserId) {
mLogger.logFingerprintAuthForWrongUser(authUserId);
return;
}
if (isFingerprintDisabled(userId)) {
mLogger.logFingerprintDisabledForUser(userId);
return;
}
onFingerprintAuthenticated(userId, isStrongBiometric);
} finally {
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
}
Trace.endSection();
}
继续走onFingerprintAuthenticated(userId, isStrongBiometric);
public void onFingerprintAuthenticated(int userId, boolean isStrongBiometric) {
Assert.isMainThread();
Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated");
mUserFingerprintAuthenticated.put(userId,
new BiometricAuthenticated(true, isStrongBiometric));
// Update/refresh trust state only if user can skip bouncer
if (getUserCanSkipBouncer(userId)) {
mTrustManager.unlockedByBiometricForUser(userId, FINGERPRINT);
}
// Don't send cancel if authentication succeeds
mFingerprintCancelSignal = null;
mLogger.logFingerprintSuccess(userId, isStrongBiometric);
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_UPDATED_FP_AUTHENTICATED);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onBiometricAuthenticated(userId, FINGERPRINT, isStrongBiometric);
}
}
mHandler.sendMessageDelayed(mHandler.obtainMessage(
MSG_BIOMETRIC_AUTHENTICATION_CONTINUE), FINGERPRINT_CONTINUE_DELAY_MS);
// Only authenticate fingerprint once when assistant is visible
mAssistantVisible = false;
// Report unlock with strong or non-strong biometric
reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
Trace.endSection();
}
开始调用接口将解锁成功消息层层传递直至keyguard解锁,与face解锁逻辑一致。
可以看到在onFaceAuthenticated(userId)方法中调用了KeyguardUpdateMonitorCallback这个抽象类的onBiometricAuthenticated()抽象方法,而BiometricUnlockController extends KeyguardUpdateMonitorCallback,并注册了回调mUpdateMonitor.registerCallback(this)
@Override
public void onBiometricAuthenticated(int userId,
BiometricSourceType biometricSourceType, boolean isStrongBiometric) {
Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
if (mUpdateMonitor.isGoingToSleep()) {
mPendingAuthenticated = new PendingAuthenticated(
userId, biometricSourceType, isStrongBiometric);
Trace.endSection();
return;
}
mBiometricType = biometricSourceType;
mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH).setType(
MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
Optional.ofNullable(BiometricUiEvent.SUCCESS_EVENT_BY_SOURCE_TYPE.get(
biometricSourceType)).ifPresent(UI_EVENT_LOGGER::log);
boolean unlockAllowed = mKeyguardBypassController.onBiometricAuthenticated(
biometricSourceType, isStrongBiometric);
if (unlockAllowed) {
mKeyguardViewMediator.userActivity();
startWakeAndUnlock(biometricSourceType, isStrongBiometric);
} else {
Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller");
}
}
直接看startWakeAndUnlock。
public void startWakeAndUnlock(BiometricSourceType biometricSourceType,
boolean isStrongBiometric) {
startWakeAndUnlock(calculateMode(biometricSourceType, isStrongBiometric));
}
public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
mMode = mode;
mHasScreenTurnedOnSinceAuthenticating = false;
if (mMode == MODE_WAKE_AND_UNLOCK_PULSING && pulsingOrAod()) {
// If we are waking the device up while we are pulsing the clock and the
// notifications would light up first, creating an unpleasant animation.
// Defer changing the screen brightness by forcing doze brightness on our window
// until the clock and the notifications are faded out.
mNotificationShadeWindowController.setForceDozeBrightness(true);
}
// During wake and unlock, we need to draw black before waking up to avoid abrupt
// brightness changes due to display state transitions.
boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled && mWakeUpDelay > 0;
Runnable wakeUp = ()-> {
if (!wasDeviceInteractive) {
if (DEBUG_BIO_WAKELOCK) {
Log.i(TAG, "bio wakelock: Authenticated, waking up...");
}
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"android.policy:BIOMETRIC");
}
if (delayWakeUp) {
mKeyguardViewMediator.onWakeAndUnlocking();
}
Trace.beginSection("release wake-and-unlock");
releaseBiometricWakeLock();
Trace.endSection();
};
if (!delayWakeUp && mMode != MODE_NONE) {
wakeUp.run();
}
switch (mMode) {
case MODE_DISMISS_BOUNCER:
case MODE_UNLOCK_FADING:
Trace.beginSection("MODE_DISMISS_BOUNCER or MODE_UNLOCK_FADING");
mKeyguardViewController.notifyKeyguardAuthenticated(
false /* strongAuth */);
Trace.endSection();
break;
case MODE_UNLOCK_COLLAPSING:
case MODE_SHOW_BOUNCER:
Trace.beginSection("MODE_UNLOCK_COLLAPSING or MODE_SHOW_BOUNCER");
if (!wasDeviceInteractive) {
mPendingShowBouncer = true;
} else {
showBouncer();
}
Trace.endSection();
break;
case MODE_WAKE_AND_UNLOCK_FROM_DREAM:
case MODE_WAKE_AND_UNLOCK_PULSING:
case MODE_WAKE_AND_UNLOCK:
if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
mMediaManager.updateMediaMetaData(false /* metaDataChanged */,
true /* allowEnterAnimation */);
} else if (mMode == MODE_WAKE_AND_UNLOCK){
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
} else {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
mUpdateMonitor.awakenFromDream();
}
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
if (delayWakeUp) {
mHandler.postDelayed(wakeUp, mWakeUpDelay);
} else {
mKeyguardViewMediator.onWakeAndUnlocking();
}
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
}
Trace.endSection();
break;
case MODE_ONLY_WAKE:
case MODE_NONE:
break;
}
mStatusBar.notifyBiometricAuthModeChanged();
Trace.endSection();
}
如果当前是在或者要进入Bouncer界面,就走mKeyguardViewController.notifyKeyguardAuthenticated。
public void notifyKeyguardAuthenticated(boolean strongAuth) {
ensureView();
mKeyguardView.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
}
@Override
public void finish(boolean strongAuth, int targetUserId) {
// If there's a pending runnable because the user interacted with a widget
// and we're leaving keyguard, then run it.
boolean deferKeyguardDone = false;
if (mDismissAction != null) {
deferKeyguardDone = mDismissAction.onDismiss();
mDismissAction = null;
mCancelAction = null;
}
if (mViewMediatorCallback != null) {
if (deferKeyguardDone) {
mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
} else {
mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
}
}
}
private void tryKeyguardDone() {
if (DEBUG) {
Log.d(TAG, "tryKeyguardDone: pending - " + mKeyguardDonePending + ", animRan - "
+ mHideAnimationRun + " animRunning - " + mHideAnimationRunning);
}
if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
handleKeyguardDone();
} else if (!mHideAnimationRun) {
if (DEBUG) Log.d(TAG, "tryKeyguardDone: starting pre-hide animation");
mHideAnimationRun = true;
mHideAnimationRunning = true;
mKeyguardViewControllerLazy.get()
.startPreHideAnimation(mHideAnimationFinishedRunnable);
}
}
如果是MODE_WAKE_AND_UNLOCK,就走mKeyguardViewMediator.onWakeAndUnlocking()
public void onWakeAndUnlocking() {
Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
mWakeAndUnlocking = true;
keyguardDone();
Trace.endSection();
}
后面解锁流程就不看了,本文主要是介绍指纹相关的流程。