Android10.0 人脸解锁流程分析

news2024/11/19 1:33:31

人脸解锁概述

人脸解锁即用户通过注视设备的正面方便地解锁手机或平板。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 目录下的源代码。
hardware/interfaces/biometrics/face/1.0/IBiometricsFace.hal

package 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);
};

hardware/interfaces/biometrics/face/1.0/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);
};

供应商(主要是手机厂商)需要实现上述接口的方法并集成人脸识别算法,完成录入和认证等的底层实现。
hardware/interfaces/biometrics/face/1.0/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方法:
frameworks/base/services/core/java/com/android/server/policy/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锁屏核心类。
frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.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)。
frameworks/base/packages/SystemUI/src/com/android/keyguard/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);
    }

屏幕超时息屏堆栈:

12-10 09:43:41.437  1468  1468 D updateFaceListeningState: java.lang.Throwable
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2128)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateBiometricListeningState(KeyguardUpdateMonitor.java:2053)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.setKeyguardGoingAway(KeyguardUpdateMonitor.java:575)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.handleKeyguardGoingAway(KeyguardUpdateMonitor.java:1727)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.access$5000(KeyguardUpdateMonitor.java:143)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor$16.handleMessage(KeyguardUpdateMonitor.java:1872)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Handler.dispatchMessage(Handler.java:106)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Looper.loop(Looper.java:223)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.app.ActivityThread.main(ActivityThread.java:7945)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at java.lang.reflect.Method.invoke(Native Method)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
12-10 09:43:41.437  1468  1468 V KeyguardUpdateMonitor:         at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2129)

电源键息屏堆栈:


12-10 09:43:41.437  1468  1468 D updateFaceListeningState: java.lang.Throwable
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2128)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.updateBiometricListeningState(KeyguardUpdateMonitor.java:2053)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.setKeyguardGoingAway(KeyguardUpdateMonitor.java:575)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.handleKeyguardGoingAway(KeyguardUpdateMonitor.java:1727)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor.access$5000(KeyguardUpdateMonitor.java:143)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.keyguard.KeyguardUpdateMonitor$16.handleMessage(KeyguardUpdateMonitor.java:1872)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Handler.dispatchMessage(Handler.java:106)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.os.Looper.loop(Looper.java:223)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at android.app.ActivityThread.main(ActivityThread.java:7945)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at java.lang.reflect.Method.invoke(Native Method)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)
12-10 09:43:41.437  1468  1468 D updateFaceListeningState:      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
12-10 09:43:41.437  1468  1468 V KeyguardUpdateMonitor:         at com.android.keyguard.KeyguardUpdateMonitor.updateFaceListeningState(KeyguardUpdateMonitor.java:2129)

这里通过handler发送消息让:handleStartedGoingToSleep处理
frameworks/base/packages/SystemUI/src/com/android/keyguard/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(),更新人脸状态。
frameworks/base/packages/SystemUI/src/com/android/keyguard/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()
frameworks/base/packages/SystemUI/src/com/android/keyguard/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()
frameworks/base/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java

// 开始验证
    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中实现。
frameworks/base/services/core/java/com/android/server/biometrics/face/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堆栈:

12-10 16:33:49.998  1017  1017 D longzhiye  : longzhiye:FaceService.java ServiceListenerImpl onAuthenticationSucceeded()
12-10 16:33:49.998  1017  1017 D longzhiye  : java.lang.Throwable
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService$ServiceListenerImpl.onAuthenticationSucceeded(FaceService.java:918)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.AuthenticationClient.onAuthenticated(AuthenticationClient.java:235)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService$FaceAuthClient.onAuthenticated(FaceService.java:297)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.BiometricServiceBase.handleAuthenticated(BiometricServiceBase.java:729)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService.access$11801(FaceService.java:110)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.FaceService$1.lambda$onAuthenticated$2$FaceService$1(FaceService.java:1040)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.biometrics.face.-$$Lambda$FaceService$1$GcU4ZG1fdDLhKvSxuMwfPargEnI.run(Unknown Source:8)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at android.os.Handler.handleCallback(Handler.java:938)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at android.os.Handler.dispatchMessage(Handler.java:99)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at android.os.Looper.loop(Looper.java:223)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.SystemServer.run(SystemServer.java:647)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.server.SystemServer.main(SystemServer.java:431)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at java.lang.reflect.Method.invoke(Native Method)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)
12-10 16:33:49.998  1017  1017 D longzhiye  :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:925)

根据前面的讲的 底层 Face HIDL 可以知道 IExtBiometricsFaceClientCallback 是回调人脸识别结果的。onAuthenticated()是当一张人脸被成功认证时被回调。
frameworks/base/services/core/java/com/android/server/biometrics/face/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("longzhiye","longzhiye: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("longzhiye","longzhiye 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()
frameworks/base/services/core/java/com/android/server/biometrics/sensors/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()
frameworks/base/core/java/android/hardware/face/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() 方法。
frameworks/base/core/java/android/hardware/face/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()
可以看一个堆栈图:

12-10 16:33:50.024  1414  1414 D longzhiye  : java.lang.Throwable
12-10 16:33:50.024  1414  1414 D longzhiye  :      at com.android.keyguard.KeyguardUpdateMonitor$15.onAuthenticationSucceeded(KeyguardUpdateMonitor.java:1427)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.hardware.face.FaceManager.sendAuthenticatedSucceeded(FaceManager.java:1212)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.hardware.face.FaceManager.access$1300(FaceManager.java:63)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.hardware.face.FaceManager$MyHandler.handleMessage(FaceManager.java:1120)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.os.Handler.dispatchMessage(Handler.java:106)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.os.Looper.loop(Looper.java:223)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at android.app.ActivityThread.main(ActivityThread.java:7945)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at java.lang.reflect.Method.invoke(Native Method)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)
12-10 16:33:50.024  1414  1414 D longzhiye  :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

frameworks/base/packages/SystemUI/src/com/android/keyguard/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("longzhiye","longzhiye",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()
frameworks/base/packages/SystemUI/src/com/android/keyguard/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
frameworks/base/packages/SystemUI/src/com/android/keyguard/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()
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/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
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/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()
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

    public void onWakeAndUnlocking() {
        Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
        mWakeAndUnlocking = true;
        /*重点关注*/
        keyguardDone();
        Trace.endSection();
    }

KeyguardViewMediator#keyguardDone()
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/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()
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

    private void handleKeyguardDone() {
        Trace.beginSection("KeyguardViewMediator#handleKeyguardDone");
        final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
        // 省略部分代码......
        /*
         * 重点关注
         * 处理隐藏
        **/
        handleHide();
        Trace.endSection();
    }

KeyguardViewMediator# handleHide()
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/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()
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/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()。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1338257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为OD机试 - 推荐多样性(Java JS Python C)

题目描述 推荐多样性需要从多个列表中选择元素,一次性要返回 N 屏数据(窗口数量),每屏展示 K 个元素(窗口大小),选择策略: 各个列表元素需要做穿插处理,即先从第一个列表中为每屏选择一个元素,再从第二个列表中为每屏选择一个元素,依次类推每个列表的元素尽量均分为…

wireshark access/trunk/hybrid报文分析

1&#xff0c;access接口 发送带vlan的报文 wireshark交换机配置 [Huawei-GigabitEthernet0/0/1] [Huawei-GigabitEthernet0/0/1]port link-type access [Huawei-GigabitEthernet0/0/1]port default vlan 100 [Huawei-GigabitEthernet0/0/2]port link-type access [Huawei-Gig…

前端开发之通过vue-office组件实现文件预览

前端开发之通过vue-office组件实现文件预览 前言效果图docx文件xlsx文件pdf文件 vue中简单案例1、安装组件2、vue中代码 前言 在实现文件预览的时候我们可以通过vue-office组件来实现文件的预览效果 效果图 docx文件 xlsx文件 pdf文件 vue中简单案例 1、安装组件 整体安装…

LoongArch指令集-特权指令系统——摘抄自胡伟武体系结构和龙芯架构32位精简版参考手册

例外与中断 1 中断 1.1 中断类型 龙芯架构 32 位精简版下的中断采用线中断的形式。每个处理器核内部可记录 12 个线中断&#xff0c;分别是&#xff1a;1 个核间中断&#xff08;IPI&#xff09;&#xff0c;1 个定时器中断&#xff08;TI&#xff09;&#xff0c;8 个硬中断…

Muscles|Tissue —— Workflow

目录 Muscles pass Tissue pass Skin pass Simulation transfer Muscles pass Muscles & Tissue的第一阶段内&#xff0c;为模拟创建muscle pass&#xff0c;会创建solid肌肉几何体&#xff08;用动画骨骼移动和弯曲&#xff09;&#xff0c;然后驱动下游组织的大部分变…

1.SQL - 概述

1. SQL语句分类 • 数据定义语言&#xff1a;简称DDL(Data Definition Language)&#xff0c;用来定义数据库对象&#xff1a;数据库&#xff0c;表&#xff0c;列等。关键字&#xff1a;create&#xff0c;alter&#xff0c;drop等 • 数据操作语言&#xff1a;简称DML(Data …

13.鸿蒙HarmonyOS App(JAVA)文本框组件按钮点击提示

13.鸿蒙HarmonyOS App(JAVA)文本框按钮点击提示 点击按钮触发组件状态&#xff0c;点击改变颜色 文本框组件&#xff0c;文本居中&#xff0c;斜体&#xff0c;左右对齐&#xff0c;点击显示提示信息 Button button(Button) findComponentById(ResourceTable.Id_btn_1); but…

【cesium-5】鼠标交互与数据查询

scene.pick返回的是包含给定窗口位置基元的对象 scene.drillpack返回的是给定窗口位置所有对象的列表 Globe.pick返回的是给光线和地形的交点 Cesium.ScreenSpaceEventType.MIDDLE_CLICK 鼠标中间点击事件 Cesium.ScreenSpaceEventType.MOUSE_MOVE 鼠标移入事件 Cesium.ScreenS…

【自然语言处理】第2部分:识别文本中的个人身份信息

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

模拟EXCEL排序

7-78 模拟EXCEL排序 分数 25 全屏浏览题目 作者 陈越 单位 浙江大学 Excel可以对一组纪录按任意指定列排序。现请编写程序实现类似功能。 输入格式: 输入的第一行包含两个正整数N(≤105) 和C&#xff0c;其中N是纪录的条数&#xff0c;C是指定排序的列号。之后有 N行&am…

蓝桥杯c/c++程序设计——数位排序

数位排序【第十三届】【省赛】【C组】 题目描述 小蓝对一个数的数位之和很感兴趣&#xff0c;今天他要按照数位之和给数排序。 当两个数各个数位之和不同时&#xff0c;将数位和较小的排在前面&#xff0c;当数位之和相等时&#xff0c;将数值小的排在前面。 例如&#xff0…

Java—Throwing Exceptions

一、指定方法引发的异常 上一节展示了如何为ListOfNumbers类中的writeList&#xff08;&#xff09;方法编写异常处理程序。有时&#xff0c;代码捕获可能在其中发生的异常是适当的。然而&#xff0c;在其他情况下&#xff0c;最好让调用堆栈更上层的方法处理该异常。例如&…

echarts自定义鼠标移上去显示,自定义图例,自定义x轴显示

提示&#xff1a;记录一下echarts常用配置,以免后期忘记 1.自定义鼠标移上去效果 tooltip: { show: true, trigger: "axis", axisPointer: { type: "shadow",//默认自定义效果 }, // //自定义鼠标移上去效果 formatter: (v) > { console.log("打印…

postman入门使用

前言 对于postman的基础其实很容易上手实现&#xff0c;也有很多教程。 对于小编我来说&#xff0c;也基本可以实现开发任务。 但是今年我们的高级测试&#xff0c;搞了一下postman&#xff0c;省去很多工作&#xff0c;让我感觉很有必要学一下 这篇文章是在 高级测试工程师ht…

云计算:OpenStack 配置二层物理网卡为三层桥的接口

目录 一、理论 1.OpenStack 二、实验 1. Linux系统修改网卡 2.OpenStack 配置二层物理网卡为三层桥的接口 一、理论 1.OpenStack &#xff08;1&#xff09;概念 OpenStack是一个开源的云计算管理平台项目&#xff0c;是一系列软件开源项目的组合。由NASA(美国国家航空…

7.3 uvm_config_db in UVM

uvm_config_db类派生自uvm_resource_db类。它是uvm_resource_db顶部的另一层便利层&#xff0c;简化了用于uvm_component实例的基本接口&#xff08;资源库的访问方法&#xff09;。 下面uvm_config_db类的代码段取自uvm源代码。 class uvm_config_db#(type Tint) extends uv…

Spring Boot:Spring Boot 入门、yaml 配置文件给属性赋值、自动装配原理详解

文章目录 Spring Boot - 01一、概述二、第一个 Spring Boot 程序补充知识 三、配置文件1. yaml 配置文件2. 使用 yaml 配置文件给属性赋值3. 松散绑定以及数据校验4. 配置文件的位置以及多环境配置 四、Spring Boot 分析1. pom.xml2. 启动器3. 主程序4. 自动装配原理5. 主启动类…

后缀表达式C语言

解析&#xff1a; 我们把数组排序&#xff0c;把较大的数字相加&#xff0c;较小的数字也相加&#xff0c;在做差就得到结果。 #include <stdio.h> int main(){int m,n,j,i;scanf("%d%d",&n,&m);//n个加号&#xff0c;m个减号。 int num[nm1];for(i0…

虹科方案丨L2进阶L3,数据采集如何助力自动驾驶

来源&#xff1a;康谋自动驾驶 虹科方案丨L2进阶L3&#xff0c;数据采集如何助力自动驾驶 原文链接&#xff1a;https://mp.weixin.qq.com/s/qhWy11x_-b5VmBt86r4OdQ 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 12月14日&#xff0c;宝马集团宣布&#xff0c;搭载…

Ubuntu20.04配置

新建用户 sudo adduser username给用户sudo权限 新创建的用户没有root权限&#xff0c;我们执行以下命令给用户sudo权限 sudo usermod -a -G adm username sudo usermod -a -G sudo username删除用户 删除用户及用户所有文件&#xff08;/home/username/路径下的所有文件&a…