学习笔记:
人脸解锁概述
人脸解锁即用户通过注视装备的正面方便地解锁手机或平板。Android 10 为支持人脸解锁的装备在人脸认证期间添加了一个新的可以安全处理相机帧、保持隐私与安全的人脸认证栈的支持,也为安全合规地启用集成生意业务的应用(网上银行或其他服务)提供了一种轻易实现的方式。
Android 原生的人脸认证栈在 Android 10 是一种新的实现,与 Android P 不一样了。新的实现先容了 IBiometricsFace.hal ,IBiometricsFaceClientCallback.hal 和 types.hal 这些接口。比方:我这边的源码都是 extends 以上接口,举行了些扩展后再实现的。
底层 Face HIDL简单熟悉
为了实现 Face HIDL,必须在供应商 (vendor) 指定的库 (library) 里实现 IBiometricsFace.hal 的全部方法。接下来我们就来看看 hardware/interfaces/biometrics/face/1.0/ 目次下的源代码(这里的源码)。
IBiometricsFace.hal
// hardware/interfaces/biometrics/face/1.0/IBiometricsFace.halpackage android.hardware.biometrics.face@1.0;import IBiometricsFaceClientCallback;/** * 用于人脸认证的 HAL 接口 */interface IBiometricsFace { /** * 设置当前的客户端回调 */ @callflow(next={"setActiveUser"}) @entry setCallback(IBiometricsFaceClientCallback clientCallback) generates (OptionalUint64 result); /** * 设置全部随后的 HAL 操作作用于上面的活泼用户 */ @callflow(next={"authenticate", "generateChallenge", "enumerate", "remove"}) setActiveUser(int32_t userId, string storePath) generates (Status status); /** * 天生随机数,用于 token 校验 */ @callflow(next={"enroll", "revokeChallenge", "setFeature"}) generateChallenge(uint32_t challengeTimeoutSec) generates (OptionalUint64 result); /** * 录入一张用户的人脸 */ @callflow(next={"cancel", "enroll", "revokeChallenge", "remove"}) enroll(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures) generates (Status status); /** * 打消随机数 */ @callflow(next={"authenticate", "setActiveUser", "enumerate", "remove"}) revokeChallenge() generates (Status status); setFeature(Feature feature, bool enabled, vec<uint8_t> hat, uint32_t faceId) generates(Status status); getFeature(Feature feature, uint32_t faceId) generates (OptionalBool result); /** * 返回和当前人脸集关联的标识符 (ID),认证者 ID */ @callflow(next={"authenticate"}) getAuthenticatorId() generates (OptionalUint64 result); /** * 取消当前的录入、认证、删除人脸或罗列人脸的操作 */ @callflow(next={"authenticate", "enroll", "enumerate", "remove", "setActiveUser"}) cancel() generates (Status status); /** * 罗列正在利用体系的用户的全部人脸模板 */ @callflow(next={"remove", "enroll", "authenticate", "setActiveUser"}) enumerate() generates (Status status); /** * 删除正在利用体系的用户的一个或全部人脸模板 */ @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId", "setActiveUser"}) remove(uint32_t faceId) generates (Status status); /** * 认证当前用户是否登录体系的用户 */ @callflow(next={"cancel", "generateChallenge", "remove"}) authenticate(uint64_t operationId) generates (Status status); userActivity() generates (Status status); /** * 为当前用户重置禁用状态 */ resetLockout(vec<uint8_t> hat) generates (Status status);};IBiometricsFaceClientCallback.hal
package android.hardware.biometrics.face@1.0;/** * 这个回调接口被客户端用来吸收人脸 HAL 的(状态)更新 */interface IBiometricsFaceClientCallback { /** * 当录入的步调完成时被回调 */ oneway onEnrollResult(uint64_t deviceId, uint32_t faceId, int32_t userId, uint32_t remaining); /** * 当一张人脸被乐成认证时被回调 */ oneway onAuthenticated(uint64_t deviceId, uint32_t faceId, int32_t userId, vec<uint8_t> token); /** * 当底层得到一张人脸时被回调 */ oneway onAcquired(uint64_t deviceId, int32_t userId, FaceAcquiredInfo acquiredInfo, int32_t vendorCode); /** * 当错误发生时被回调 */ oneway onError(uint64_t deviceId, int32_t userId, FaceError error, int32_t vendorCode); /** * 当人脸模板被删除时被回调 */ oneway onRemoved(uint64_t deviceId, vec<uint32_t> removed, int32_t userId); /** * 罗列全部人脸模板的回调 */ oneway onEnumerate(uint64_t deviceId, vec<uint32_t> faceIds, int32_t userId); /** * 当禁用状态改变时被回调 */ oneway onLockoutChanged(uint64_t duration);};应商(重要是手机厂商)必要实现上述接口的方法并集成人脸辨认算法,完成录入和认证等的底层实现。
types.hal
package android.hardware.biometrics.face@1.0;/* * 在这里 setActiveUser 不会被调用,全部错误消息会返回这个用户 ID */enum UserHandle : int32_t { NONE = -1};/** * 状态码 */enum Status : uint32_t { /** * 方法被乐成调用 */ OK = 0, /** * 方法调用的参数之一无效 */ ILLEGAL_ARGUMENT = 1, /** * 人脸 HAL 不支持这个操作 */ OPERATION_NOT_SUPPORTED = 2, /** * HAL 遭遇内部错误,不能完成请求 */ INTERNAL_ERROR = 3, /** * 没有录入人脸 */ NOT_ENROLLED = 4};enum Feature : uint32_t { /** * 要求注视 */ REQUIRE_ATTENTION = 1, /** * 要求录入时姿势多样(有变革) */ REQUIRE_DIVERSITY = 2};/** * onError 回调的人脸错误消息 */enum FaceError : int32_t { /** * 不能被分析的硬件错误 */ HW_UNAVAILABLE = 1, /** * 不能处理当前操作 */ UNABLE_TO_PROCESS = 2, /** * 超时 */ TIMEOUT = 3, /** * 没有充足的存储空间去完成当前的操作 */ NO_SPACE = 4, /** * 被取消 */ CANCELED = 5, /** * 无法删除 */ UNABLE_TO_REMOVE = 6, /** * 30s 禁用 */ LOCKOUT = 7, /** * 用来开启供应商指定的错误消息 */ VENDOR = 8, /** * 禁用直到利用主身份认证 */ LOCKOUT_PERMANENT = 9};/** * 向客户端反馈获取人脸的消息(质量),以便用户做出相应的改变 */enum FaceAcquiredInfo : int32_t { GOOD = 0, /** * 无效人脸 */ INSUFFICIENT = 1, /** * 人脸太亮 */ TOO_BRIGHT = 2, /** * 人脸太暗 */ TOO_DARK = 3, /** * 人脸太近 */ TOO_CLOSE = 4, /** * 人脸太远 */ TOO_FAR = 5, /** * 人脸太高,只有下半部分 */ FACE_TOO_HIGH = 6, /** * 人脸太低 */ FACE_TOO_LOW = 7, /** * 人脸偏右 */ FACE_TOO_RIGHT = 8, /** * 人脸偏左 */ FACE_TOO_LEFT = 9, /** * 注视不佳 */ POOR_GAZE = 10, /** * 未检测到人脸 */ NOT_DETECTED = 11, /** * 检测到运动过多 */ TOO_MUCH_MOTION = 12, /** * 重新校正 */ RECALIBRATE = 13, /** * 和前一帧差别太大 */ TOO_DIFFERENT = 14, /** * 和前一帧太相似 */ TOO_SIMILAR = 15, /** * 摇射角度太大,直面相机角度为 0 */ PAN_TOO_EXTREME = 16, /** * 倾斜角度太大 */ TILT_TOO_EXTREME = 17, /** * 侧倾角幅度太大 */ ROLL_TOO_EXTREME = 18, /** * 人脸被遮挡 */ FACE_OBSCURED = 19, START = 20, /** * 传感器(摄像头)脏了 */ SENSOR_DIRTY = 21, /** * 用于开启供应商指定的获取人脸的消息 */ VENDOR = 22};/** * 结果 */struct OptionalUint64 { /** * 返回的状态 */ Status status; /** * 只意味着状态是 OK 的 */ uint64_t value;};/** * 结果 */struct OptionalBool { /** * 返回的状态 */ Status status; /** * 只意味着状态是 OK 的 */ bool value;};人脸辨认调用流程(注册监听、捕获人脸、比对)
人脸解锁的入口在Keyguard中,但要从
息屏的处理是从PowerManager开始,终极到锁屏的焦点类KeyguardViewMediator,息屏处理的大抵流程如下:
前面几步就跳过,直接从PhoneWindowManager开始分析。灭屏之后会调用PhoneWindowManager的startedGoingToSleep方法:
// PhoneWindowManager.java // 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); } }在该方法中又调用了KeyguardServiceDelegate类的onStartedGoingToSleep方法。
KeyguardServiceDelegate#onStartedGoingToSleep →KeyguardServiceWrapper#onStartedGoingToSleep → KeyguardService#onStartedGoingToSleep → KeyguardViewMediator#onStartedGoingToSleep,终极会调用到KeyguardViewMediator锁屏焦点类。
// KeyguardViewMediator.java public void onStartedGoingToSleep(int why) { if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + why + ")"); synchronized (this) { mDeviceInteractive = false; mGoingToSleep = true; // 这位置的代码作用详细不知,但放在前面可以办理息屏后又立马利用指纹解锁时:出现1.2s内没反应的题目。 mUpdateMonitor.dispatchKeyguardGoingAway(false); // Lock immediately based on setting if secure (user has a pin/pattern/password). // This also "locks" the device when not secure to provide easy access to the // camera while preventing unwanted input. int currentUser = KeyguardUpdateMonitor.getCurrentUser(); final boolean lockImmediately = mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser) || !mLockPatternUtils.isSecure(currentUser); long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser()); mLockLater = false; // 省略部分代码...... //判定是否必要播放锁屏音 if (mPendingLock) { playSounds(true); } } // 使得KeyguardUpdateMonitor可以监听到GoingToSleep // KeyguardUpdateMonitor 是Keyguard更新监视器 mUpdateMonitor.dispatchStartedGoingToSleep(why); //关照开始息屏 notifyStartedGoingToSleep(); }这里重要分析的是屏幕自己息屏,则重点关注mUpdateMonitor.dispatchStartedGoingToSleep(why)。
// KeyguardUpdateMonitor.java // 等待屏幕超时息屏,handler会发送 MSG_STARTED_GOING_TO_SLEEP public void dispatchStartedGoingToSleep(int why) { mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, 0)); } // 注意:如果说按电源键息屏,handler会发送 MSG_STARTED_WAKING_UP public void dispatchStartedWakingUp() { synchronized (this) { mDeviceInteractive = true; } mHandler.sendEmptyMessage(MSG_STARTED_WAKING_UP); }屏幕超时息屏堆栈:
09-14 09:43:41.437 1468 1468 D updateFaceListeningState: java.lang.Throwable09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2128)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.updateBiometricListeningState(KeyguardUpdateMonitor.java:2053)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.setKeyguardGoingAway(KeyguardUpdateMonitor.java:575)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.handleKeyguardGoingAway(KeyguardUpdateMonitor.java:1727)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.access$5000(KeyguardUpdateMonitor.java:143)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor$16.handleMessage(KeyguardUpdateMonitor.java:1872)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at android.os.Handler.dispatchMessage(Handler.java:106)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at android.os.Looper.loop(Looper.java:223)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at android.app.ActivityThread.main(ActivityThread.java:7945)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at java.lang.reflect.Method.invoke(Native Method)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)09-14 09:43:41.437 1468 1468 V KeyguardUpdateMonitor: at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2129)电源键息屏堆栈:
09-14 09:43:41.437 1468 1468 D updateFaceListeningState: java.lang.Throwable09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2128)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.updateBiometricListeningState(KeyguardUpdateMonitor.java:2053)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.setKeyguardGoingAway(KeyguardUpdateMonitor.java:575)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.handleKeyguardGoingAway(KeyguardUpdateMonitor.java:1727)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor.access$5000(KeyguardUpdateMonitor.java:143)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.keyguard.KeyguardUpdateMonitor$16.handleMessage(KeyguardUpdateMonitor.java:1872)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at android.os.Handler.dispatchMessage(Handler.java:106)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at android.os.Looper.loop(Looper.java:223)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at android.app.ActivityThread.main(ActivityThread.java:7945)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at java.lang.reflect.Method.invoke(Native Method)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)09-14 09:43:41.437 1468 1468 D updateFaceListeningState: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)09-14 09:43:41.437 1468 1468 V KeyguardUpdateMonitor: at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2129)
这里通过handler发送消息让:handleStartedGoingToSleep处理
// KeyguardUpdateMonitor.java protected void handleStartedGoingToSleep(int arg1) { checkIsHandlerThread(); 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(); } private void updateBiometricListeningState() { updateFingerprintListeningState(); updateFaceListeningState(); }在这篇文章里,我们只必要关注updateFaceListeningState(),更新人脸状态。
// KeyguardUpdateMonitor.java private void updateFaceListeningState() { // 如果此消息存在,我们不应再次举行身份验证 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(); } }startListeningForFace()
// KeyguardUpdateMonitor.java private void startListeningForFace() { if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) { setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING); return; } if (DEBUG) Log.v(TAG, "startListeningForFace()"); int userId = getCurrentUser(); if (isUnlockWithFacePossible(userId)) { if (mFaceCancelSignal != null) { mFaceCancelSignal.cancel(); } mFaceCancelSignal = new CancellationSignal(); /*重点关注*/ mFaceManager.authenticate(null, mFaceCancelSignal, 0, mFaceAuthenticationCallback, null, userId); setFaceRunningState(BIOMETRIC_STATE_RUNNING); } }FaceManager#authenticate()
// frameworks/base/core/java/android/hardware/face/FaceManager.java public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler, int userId) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } if(mPendingFaceAuth != null) { Log.w(TAG, "authentication too frequent"); } if(mAuthenticationCallback != null) { mPendingFaceAuth = new PendingFaceAuth(crypto, cancel, flags, callback, handler, userId); Log.w(TAG, "pengding face auth"); return; } else { /*重点关注*/ authenticateInternel(crypto, cancel, flags, callback, handler, userId); } } void authenticateInternel(CryptoObject crypto, CancellationSignal cancel, int flags, AuthenticationCallback callback, Handler handler, int userId) { if (cancel != null) { if (cancel.isCanceled()) { Log.w(TAG, "authentication already canceled"); return; } else { cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); } } //mSurface = null; //onFaceidStarted(); if (mService != null) { try { useHandler(handler); mAuthenticationCallback = callback; mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; Trace.beginSection("FaceManager#authenticate"); /*重点关注*/ // 举行人脸认证 mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, mContext.getOpPackageName()); /* UNISOC: Modify for bug1374210 {@ */ if (callback != null) { callback.onAuthenticationStarted(); } /* @} */ } catch (RemoteException e) { // 省略部分代码...... } finally { Trace.endSection(); } } }FaceService#authenticate()
// frameworks/base/services/core/java/com/android/server/biometrics/face/FaceService.java @Override // Binder call public void authenticate(final IBinder token, final long opId, int userId, final IFaceServiceReceiver receiver, final int flags, final String opPackageName) { checkPermission(USE_BIOMETRIC_INTERNAL); updateActiveGroup(userId, opPackageName); final boolean restricted = isRestricted(); final AuthenticationClientImpl client = new FaceAuthClient(getContext(), mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, 0 /* cookie */, false /* requireConfirmation */); /*重点关注*/ authenticateInternal(client, opId, opPackageName); }BiometricServiceBase#authenticateInternal()
protected void authenticateInternal(AuthenticationClientImpl client, long opId, String opPackageName) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId); } protected void authenticateInternal(AuthenticationClientImpl client, long opId, String opPackageName, int callingUid, int callingPid, int callingUserId) { if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid, callingUserId)) { if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName); return; } mHandler.post(() -> { mMetricsLogger.histogram(getConstants().tagAuthToken(), opId != 0L ? 1 : 0); // Get performance stats object for this user. HashMap<Integer, PerformanceStats> pmap = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap; PerformanceStats stats = pmap.get(mCurrentUserId); if (stats == null) { stats = new PerformanceStats(); pmap.put(mCurrentUserId, stats); } mPerformanceStats = stats; mIsCrypto = (opId != 0); /*重点关注*/ startAuthentication(client, opPackageName); }); } private void startAuthentication(AuthenticationClientImpl client, String opPackageName) { if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")"); int lockoutMode = getLockoutMode(); // getLockoutMode() 判定是否锁定,会返回一个 int 值 if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) { Slog.v(getTag(), "In lockout mode(" + lockoutMode + ") ; disallowing authentication"); int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT : BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) { Slog.w(getTag(), "Cannot send permanent lockout message to client"); } return; } /*重点关注*/ startClient(client, true /* initiatedByClient */); //这里将AuthenticationClient转达进去 } private void startClient(ClientMonitor newClient, boolean initiatedByClient) { ClientMonitor currentClient = mCurrentClient; if (currentClient != null) { if (DEBUG) Slog.v(getTag(), "request stop current client " + currentClient.getOwnerString()); if (currentClient instanceof InternalEnumerateClient || currentClient instanceof InternalRemovalClient) { // 省略部分代码...... } else { currentClient.stop(initiatedByClient); mHandler.removeCallbacks(mResetClientState); mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT); } mPendingClient = newClient; } else if (newClient != null) { // 省略部分代码...... // We are not a BiometricPrompt client, start the client immediately mCurrentClient = newClient; /*重点关注*/ startCurrentClient(mCurrentClient.getCookie()); //这里继承将AuthenticationClient转达进去 } } protected void startCurrentClient(int cookie) { // 省略部分代码...... /*重点关注*/ //这里调用的是AuthenticationClient的start方法 int status = mCurrentClient.start(); if (status == 0) { notifyClientActiveCallbacks(true); } // ... ... }mCurrentClient是ClientMonitor的对象,而AuthenticationClient继承了ClientMonitor类;
AuthenticationClient#start()
// 开始验证 public int start() { mStarted = true; onStart(); try { /*重点关注*/ // 获取 DaemonWrappe 对象开始鉴权,这里如果鉴权完成会回调注册的 ClientMonito r的 onAuthenticated 接口 //到这一步 DaemonWrappe 对象 进入等待捕获人脸信息,摄像头会给到DaemonWrappe对象人脸信息。 // 这里对调用到 DaemonWrapper 在 FaceService 里有实现,在那里会直接调用到 HAL 层 final int result = getDaemonWrapper().authenticate(mOpId, getGroupId()); if (result != 0) { Slog.w(getLogTag(), "startAuthentication failed, result=" + result); mMetricsLogger.histogram(mConstants.tagAuthStartError(), result); onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); return result; } if (DEBUG) Slog.w(getLogTag(), "client " + getOwnerString() + " is authenticating..."); } catch (RemoteException e) { Slog.e(getLogTag(), "startAuthentication failed", e); return ERROR_ESRCH; } return 0; // success }start方法会调用faced,调用底层的人脸库,底层库返回结果后会调用onAuthenticated来反馈结果给receiver,在往上层反馈。
增补:IExtBiometricsFace.hal 这个接口在 ExtBiometricsFace.cpp中实现。
// FaceService.java @Override public void onStart() { super.onStart(); // 在初始化后会创建和HAL层的通讯,即毗连到 FaceService, //并通过getFaceDaemon()拿到用于通讯的 IExtBiometricsFace对象(binder) publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper()); SystemServerInitThreadPool.submit(() -> mHandler.post(this::getFaceDaemon), TAG + ".onStart"); }屏幕解锁(结果回调、移除锁)
底层库回调onAuthenticated堆栈:
09-13 16:33:49.998 1017 1017 D yexiao : yexiao:FaceService.java ServiceListenerImpl onAuthenticationSucceeded()09-13 16:33:49.998 1017 1017 D yexiao : java.lang.Throwable09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.biometrics.face.FaceService$ServiceListenerImpl.onAuthenticationSucceeded(FaceService.java:918)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.biometrics.AuthenticationClient.onAuthenticated(AuthenticationClient.java:235)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.biometrics.face.FaceService$FaceAuthClient.onAuthenticated(FaceService.java:297)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.biometrics.BiometricServiceBase.handleAuthenticated(BiometricServiceBase.java:729)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.biometrics.face.FaceService.access$11801(FaceService.java:110)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.biometrics.face.FaceService$1.lambda$onAuthenticated$2$FaceService$1(FaceService.java:1040)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.biometrics.face.-$$Lambda$FaceService$1$GcU4ZG1fdDLhKvSxuMwfPargEnI.run(Unknown Source:8)09-13 16:33:49.998 1017 1017 D yexiao : at android.os.Handler.handleCallback(Handler.java:938)09-13 16:33:49.998 1017 1017 D yexiao : at android.os.Handler.dispatchMessage(Handler.java:99)09-13 16:33:49.998 1017 1017 D yexiao : at android.os.Looper.loop(Looper.java:223)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.SystemServer.run(SystemServer.java:647)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.server.SystemServer.main(SystemServer.java:431)09-13 16:33:49.998 1017 1017 D yexiao : at java.lang.reflect.Method.invoke(Native Method)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)09-13 16:33:49.998 1017 1017 D yexiao : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:925)根据前面的讲的 底层 Face HIDL 可以知道 IExtBiometricsFaceClientCallback 是回调人脸辨认结果的。onAuthenticated()是当一张人脸被乐成认证时被回调。
// FaceService.java /** * Receives callbacks from the HAL. */ private IExtBiometricsFaceClientCallback mDaemonCallback = new IExtBiometricsFaceClientCallback.Stub() { // 省略部分代码 ...... @Override public void onAuthenticated(final long deviceId, final int faceId, final int userId, ArrayList<Byte> token) { mHandler.post(() -> { final Face face = new Face("", faceId, deviceId); final boolean authenticated = faceId != 0; /*重点在这里*/ FaceService.super.handleAuthenticated(authenticated, face, token); }); } // 省略部分代码 ...... };通过上面 FaceService.super.handleAuthenticated(authenticated, face, token) 的调用。将会调用到:
BiometricServiceBase#handleAuthenticated()
// BiometricServiceBase.java protected void handleAuthenticated(boolean authenticated, BiometricAuthenticator.Identifier identifier, ArrayList<Byte> token) { Log.d("yexiao","yexiao:AuthenticationClient.java ----------------2 "); ClientMonitor client = mCurrentClient; // 重点在后半句判定,通过前面的分析可以知道 client 着实是 FaceAuthClient 的对象 if (client != null && client.onAuthenticated(identifier, authenticated, token)) { removeClient(client); } if (authenticated) { mPerformanceStats.accept++; } else { mPerformanceStats.reject++; } }通过前面的分析可以知道 client 着实是 FaceAuthClient 的对象,在FaceService.java 的内部类FaceServiceWrapper的authenticate()方法举行实例化传已往的。反正终极将会回调到FaceService.java 的内部类FaceAuthClient的onAuthenticated()方法
@Override public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> token) { Log.d("yexiao","yexiao:FaceAuthClient onAuthenticated ",new Throwable()); // 重点关注super final boolean result = super.onAuthenticated(identifier, authenticated, token); mUsageStats.addEvent(new AuthenticationEvent( getStartTimeMs(), System.currentTimeMillis() - getStartTimeMs() /* latency */, authenticated, 0 /* error */, 0 /* vendorError */, getTargetUserId())); // For face, the authentication lifecycle ends either when // 1) Authenticated == true // 2) Error occurred // 3) Authenticated == false // Fingerprint currently does not end when the third condition is met which is a bug, // but let's leave it as-is for now. return result || !authenticated; }这里的super将会调到父类AuthenticationClient中的onAuthenticated()。
AuthenticationClient#onAuthenticated()
// AuthenticationClient.java public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, ArrayList<Byte> token) { super.logOnAuthenticated(getContext(), authenticated, mRequireConfirmation, getTargetUserId(), isBiometricPrompt()); // 省略部分代码 ...... try { if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + authenticated + ")" + ", ID:" + identifier.getBiometricId() + ", Owner: " + getOwnerString() + ", isBP: " + isBiometricPrompt() + ", listener: " + listener + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); if (authenticated) { // 省略部分代码 ...... try { // Explicitly have if/else here to make it super obvious in case the code is // touched in the future. if (!getIsRestricted()) { /*重点关注*/ // 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 { // 省略部分代码 ...... } } catch (RemoteException e) { Slog.e(getLogTag(), "Remote exception", e); result = true; } return result; }这里的 listener 着实是 BiometricServiceBase.ServiceListener 接口的回调,BiometricServiceBase的内部类BiometricServiceListener也实现了该接口,但是没有实现onAuthenticationSucceeded() 方法,而该ServiceListener 接口在FaceService中的内部类ServiceListenerImpl 也有实现,而且实现了onAuthenticationSucceeded() 方法。以是将会回调到FaceService内部类的 ServiceListenerImpl#onAuthenticationSucceeded()。
ServiceListenerImpl#onAuthenticationSucceeded()
/** * 从 ClientMonitor 实现吸收回调。结果被转发到 FaceManager */ private class ServiceListenerImpl implements ServiceListener { private IFaceServiceReceiver mFaceServiceReceiver; public ServiceListenerImpl(IFaceServiceReceiver receiver) { mFaceServiceReceiver = receiver; } // 省略部分代码 ...... @Override public void onAuthenticationSucceeded(long deviceId, BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException { if (mFaceServiceReceiver != null) { if (biometric == null || biometric instanceof Face) { // 重点关注这里 mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric, userId, isStrongBiometric()); } else { Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric"); } } } // 省略部分代码 ...... }ServiceListenerImpl 这个类是负责将回调结果,转发到 FaceManager 中的。通过 IFaceServiceReceiver 的对象,回调 FaceManager 中的 onAuthenticationSucceeded() 方法。
FaceManager#onAuthenticationSucceeded()
// FaceManager.java private IFaceServiceReceiver mServiceReceiver = new IFaceServiceReceiver.Stub() { // 省略部分代码 ...... @Override // binder call public void onAuthenticationSucceeded(long deviceId, Face face, int userId, boolean isStrongBiometric) { mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? 1 : 0, face).sendToTarget(); //onFaceidStopped(); } // 省略部分代码 ...... };在这里通过 mHandler 发送了 MSG_AUTHENTICATION_SUCCEEDED 消息,在 handleMessage 中将会实行 sendAuthenticatedSucceeded() 方法。
// FaceManager.java private void sendAuthenticatedSucceeded(Face face, int userId, boolean isStrongBiometric) { if (mAuthenticationCallback != null) { final AuthenticationResult result = new AuthenticationResult(mCryptoObject, face, userId, isStrongBiometric); // 重要关注这里 mAuthenticationCallback.onAuthenticationSucceeded(result); mAuthenticationCallback = null; if(mPendingFaceAuth != null) { authenticateInternel(mPendingFaceAuth.mCrypto, mPendingFaceAuth.mCancel, mPendingFaceAuth.mFlags, mPendingFaceAuth.mCallback, mPendingFaceAuth.mHandler, mPendingFaceAuth.mUserId); mPendingFaceAuth = null; } } }在 sendAuthenticatedSucceeded() 方法中将会实行 BiometricAuthenticator.AuthenticationCallback 的接口的回调,将会把结果回调到 KeyguardUpdateMonitor 中FaceManager.AuthenticationCallback 的onAuthenticationSucceeded() 方法。
FaceManager.AuthenticationCallback#onAuthenticationSucceeded()
可以看一个堆栈图:
09-13 16:33:50.024 1414 1414 D yexiao : java.lang.Throwable09-13 16:33:50.024 1414 1414 D yexiao : at com.android.keyguard.KeyguardUpdateMonitor$15.onAuthenticationSucceeded(KeyguardUpdateMonitor.java:1427)09-13 16:33:50.024 1414 1414 D yexiao : at android.hardware.face.FaceManager.sendAuthenticatedSucceeded(FaceManager.java:1212)09-13 16:33:50.024 1414 1414 D yexiao : at android.hardware.face.FaceManager.access$1300(FaceManager.java:63)09-13 16:33:50.024 1414 1414 D yexiao : at android.hardware.face.FaceManager$MyHandler.handleMessage(FaceManager.java:1120)09-13 16:33:50.024 1414 1414 D yexiao : at android.os.Handler.dispatchMessage(Handler.java:106)09-13 16:33:50.024 1414 1414 D yexiao : at android.os.Looper.loop(Looper.java:223)09-13 16:33:50.024 1414 1414 D yexiao : at android.app.ActivityThread.main(ActivityThread.java:7945)09-13 16:33:50.024 1414 1414 D yexiao : at java.lang.reflect.Method.invoke(Native Method)09-13 16:33:50.024 1414 1414 D yexiao : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)09-13 16:33:50.024 1414 1414 D yexiao : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)// KeyguardUpdateMonitor.java @VisibleForTesting FaceManager.AuthenticationCallback mFaceAuthenticationCallback = new FaceManager.AuthenticationCallback() { @Override public void onAuthenticationFailed() { // 身份验证失败 handleFaceAuthFailed(); } /* UNISOC: Modify for bug1374210 {@ */ @Override public void onAuthenticationStarted() { handleFaceAuthStarted(); } /* @} */ @Override public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) { Log.d("yexiao","yexiao:onAuthenticationSucceeded",new Throwable()); Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded"); // 重点关注 handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric()); Trace.endSection(); } @Override public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { handleFaceHelp(helpMsgId, helpString.toString()); } @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { // 人脸处理操作已取消或未辨认到 handleFaceError(errMsgId, errString.toString()); } @Override public void onAuthenticationAcquired(int acquireInfo) { handleFaceAcquired(acquireInfo); } };KeyguardUpdateMonitor#handleFaceAuthenticated()
// KeyguardUpdateMonitor.java private void handleFaceAuthenticated(int authUserId) { Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated"); try { final int userId; try { userId = ActivityManager.getService().getCurrentUser().id; } catch (RemoteException e) { Log.e(TAG, "Failed to get current user id: ", e); return; } if (userId != authUserId) { Log.d(TAG, "Face authenticated for wrong user: " + authUserId); return; } if (isFaceDisabled(userId)) { Log.d(TAG, "Face authentication disabled by DPM for userId: " + userId); return; } /*重点关注*/ onFaceAuthenticated(userId); } finally { setFaceRunningState(BIOMETRIC_STATE_STOPPED); } Trace.endSection(); }handleFaceAuthenticated#onFaceAuthenticated
// KeyguardUpdateMonitor.java protected void onFaceAuthenticated(int userId) { Trace.beginSection("KeyGuardUpdateMonitor#onFaceAuthenticated"); mUserFaceAuthenticated.put(userId, true); // Update/refresh trust state only if user can skip bouncer if (getUserCanSkipBouncer(userId)) { mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FACE); } // Don't send cancel if authentication succeeds mFaceCancelSignal = null; for (int i = 0; i < mCallbacks.size(); i++) { /*重点关注*/ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { /*重点关注*/ cb.onBiometricAuthenticated(userId, BiometricSourceType.FACE); } } mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE), BIOMETRIC_CONTINUE_DELAY_MS); // Only authenticate face once when assistant is visible mAssistantVisible = false; Trace.endSection(); }这里开始调用接口将解锁乐成消息层层转达直至keyguard解锁,与指纹解锁逻辑划一
可以看到在 onFaceAuthenticated(userId) 方法中调用了 KeyguardUpdateMonitorCallback 这个抽象类的 onBiometricAuthenticated() 抽象方法,而 BiometricUnlockController extends KeyguardUpdateMonitorCallback,而且注册了回调 mUpdateMonitor.registerCallback(this)。
BiometricUnlockController #onBiometricAuthenticated()
// BiometricUnlockController.java @Override public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType, boolean isStrongBiometric) { // 省略部分代码...... if (unlockAllowed) { mKeyguardViewMediator.userActivity(); /*重点关注*/ // 开始叫醒息争锁 startWakeAndUnlock(biometricSourceType, isStrongBiometric); } else { Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller"); } }BiometricUnlockController#startWakeAndUnlock
// BiometricUnlockController.java public void startWakeAndUnlock(int mode) { // 省略部分代码...... 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(); }; // 省略部分代码...... mStatusBar.notifyBiometricAuthModeChanged(); Trace.endSection(); }KeyguardViewMediator#onWakeAndUnlocking()
// KeyguardViewMediator.java public void onWakeAndUnlocking() { Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking"); mWakeAndUnlocking = true; /*重点关注*/ keyguardDone(); Trace.endSection(); }KeyguardViewMediator#keyguardDone()
// KeyguardViewMediator.java public void keyguardDone() { Trace.beginSection("KeyguardViewMediator#keyguardDone"); if (DEBUG) Log.d(TAG, "keyguardDone()"); userActivity(); EventLog.writeEvent(70000, 2); /*重点关注*/ Message msg = mHandler.obtainMessage(KEYGUARD_DONE); mHandler.sendMessage(msg); Trace.endSection(); }keyguardDone()该方法发送了一条 KEYGUARD_DONE 消息,在 handleMessage 中将会实行 handleKeyguardDone() 方法。
KeyguardViewMediator#handleKeyguardDone()
// KeyguardViewMediator.java private void handleKeyguardDone() { Trace.beginSection("KeyguardViewMediator#handleKeyguardDone"); final int currentUser = KeyguardUpdateMonitor.getCurrentUser(); // 省略部分代码...... /* * 重点关注 * 处理潜伏 **/ handleHide(); Trace.endSection(); }KeyguardViewMediator# handleHide()
// KeyguardViewMediator.java private void handleHide() { Trace.beginSection("KeyguardViewMediator#handleHide"); // It's possible that the device was unlocked in a dream state. It's time to wake up. if (mAodShowing) { PowerManager pm = mContext.getSystemService(PowerManager.class); pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:BOUNCER_DOZING"); } synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleHide"); if (mustNotUnlockCurrentUser()) { if (DEBUG) Log.d(TAG, "Split system user, quit unlocking."); return; } mHiding = true; if (mShowing && !mOccluded) { mKeyguardGoingAwayRunnable.run(); } else { /*重点关注*/ // 处理开始键盘保护退出动画 handleStartKeyguardExitAnimation( SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(), mHideAnimation.getDuration()); } } Trace.endSection(); }KeyguardViewMediator#handleStartKeyguardExitAnimation()
// KeyguardViewMediator.java private void handleStartKeyguardExitAnimation(long startTime, long fadeoutDuration) { Trace.beginSection("KeyguardViewMediator#handleStartKeyguardExitAnimation"); // 省略部分代码...... mWakeAndUnlocking = false; setShowingLocked(false, mAodShowing); mDismissCallbackRegistry.notifyDismissSucceeded(); /*重点关注*/ mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration); resetKeyguardDonePendingLocked(); mHideAnimationRun = false; adjustStatusBarLocked(); sendUserPresentBroadcast(); } Trace.endSection(); }下面就不详细分析了,将会按如下次序实行:StatusBarKeyguardViewManager#hide()→StatusBarKeyguardViewManager#hideBouncer()→KeyguardBouncer#hide()→KeyguardBouncer#mRemoveViewRunnable→KeyguardBouncer#removeView()。
至此锁屏界面移除的逻辑根本clear |