Android10.0 人臉解鎖

學(xué)習(xí)筆記:

人臉解鎖概述

人臉解鎖即用戶通過注視設(shè)備的正面方便地解鎖手機(jī)或平板。Android 10 為支持人臉解鎖的設(shè)備在人臉認(rèn)證期間添加了一個新的可以安全處理相機(jī)幀、保持隱私與安全的人臉認(rèn)證棧的支持,也為安全合規(guī)地啟用集成交易的應(yīng)用(網(wǎng)上銀行或其他服務(wù))提供了一種容易實現(xiàn)的方式俐筋。

Android 原生的人臉認(rèn)證棧在 Android 10 是一種新的實現(xiàn),與 Android P 不一樣了。新的實現(xiàn)介紹了 IBiometricsFace.hal 路媚,IBiometricsFaceClientCallback.hal 和 types.hal 這些接口。例如:我這邊的源碼都是 extends 以上接口樊销,進(jìn)行了些擴(kuò)展后再實現(xiàn)的磷籍。

底層 Face HIDL簡單認(rèn)識

為了實現(xiàn) Face HIDL,必須在供應(yīng)商 (vendor) 指定的庫 (library) 里實現(xiàn) IBiometricsFace.hal 的所有方法现柠。接下來我們就來看看 hardware/interfaces/biometrics/face/1.0/ 目錄下的源代碼(這里的源碼)院领。

IBiometricsFace.hal

// hardware/interfaces/biometrics/face/1.0/IBiometricsFace.hal
package android.hardware.biometrics.face@1.0;

import IBiometricsFaceClientCallback;

/**
 * 用于人臉認(rèn)證的 HAL 接口
 */
interface IBiometricsFace {

    /**
     * 設(shè)置當(dāng)前的客戶端回調(diào)
     */
    @callflow(next={"setActiveUser"})
    @entry
    setCallback(IBiometricsFaceClientCallback clientCallback)
        generates (OptionalUint64 result);

    /**
     * 設(shè)置所有隨后的 HAL 操作作用于上面的活躍用戶
     */
    @callflow(next={"authenticate", "generateChallenge", "enumerate", "remove"})
    setActiveUser(int32_t userId, string storePath) generates (Status status);

    /**
     * 生成隨機(jī)數(shù),用于 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);

    /**
     * 撤銷隨機(jī)數(shù)
     */
    @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);

    /**
     * 返回和當(dāng)前人臉集關(guān)聯(lián)的標(biāo)識符 (ID)够吩,認(rèn)證者 ID
     */
    @callflow(next={"authenticate"})
    getAuthenticatorId() generates (OptionalUint64 result);

    /**
     * 取消當(dāng)前的錄入比然、認(rèn)證、刪除人臉或枚舉人臉的操作
     */
    @callflow(next={"authenticate", "enroll", "enumerate", "remove",
        "setActiveUser"})
    cancel() generates (Status status);

    /**
     * 枚舉正在使用系統(tǒng)的用戶的所有人臉模板
     */
    @callflow(next={"remove", "enroll", "authenticate", "setActiveUser"})
    enumerate() generates (Status status);

    /**
     * 刪除正在使用系統(tǒng)的用戶的一個或所有人臉模板
     */
    @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId",
        "setActiveUser"})
    remove(uint32_t faceId) generates (Status status);

    /**
     * 認(rèn)證當(dāng)前用戶是否登錄系統(tǒng)的用戶
     */
    @callflow(next={"cancel", "generateChallenge", "remove"})
    authenticate(uint64_t operationId) generates (Status status);

    userActivity() generates (Status status);

    /**
     * 為當(dāng)前用戶重置禁用狀態(tài)
     */
    resetLockout(vec<uint8_t> hat) generates (Status status);
};

IBiometricsFaceClientCallback.hal

package android.hardware.biometrics.face@1.0;

/**
 * 這個回調(diào)接口被客戶端用來接收人臉 HAL 的(狀態(tài))更新
 */
interface IBiometricsFaceClientCallback {

    /**
     * 當(dāng)錄入的步驟完成時被回調(diào)
     */
    oneway onEnrollResult(uint64_t deviceId, uint32_t faceId, int32_t userId,
        uint32_t remaining);

    /**
     * 當(dāng)一張人臉被成功認(rèn)證時被回調(diào)
     */
    oneway onAuthenticated(uint64_t deviceId, uint32_t faceId, int32_t userId,
        vec<uint8_t> token);

    /**
     * 當(dāng)?shù)讓荧@得一張人臉時被回調(diào)
     */
     oneway onAcquired(uint64_t deviceId, int32_t userId,
         FaceAcquiredInfo acquiredInfo, int32_t vendorCode);

    /**
     * 當(dāng)錯誤發(fā)生時被回調(diào)
     */
    oneway onError(uint64_t deviceId, int32_t userId, FaceError error,
        int32_t vendorCode);

    /**
     * 當(dāng)人臉模板被刪除時被回調(diào)
     */
    oneway onRemoved(uint64_t deviceId, vec<uint32_t> removed, int32_t userId);

    /**
     * 枚舉所有人臉模板的回調(diào)
     */
    oneway onEnumerate(uint64_t deviceId, vec<uint32_t> faceIds,
        int32_t userId);

    /**
     * 當(dāng)禁用狀態(tài)改變時被回調(diào)
     */
    oneway onLockoutChanged(uint64_t duration);
};

應(yīng)商(主要是手機(jī)廠商)需要實現(xiàn)上述接口的方法并集成人臉識別算法周循,完成錄入和認(rèn)證等的底層實現(xiàn)强法。

types.hal

package android.hardware.biometrics.face@1.0;

/*
 * 在這里 setActiveUser 不會被調(diào)用,所有錯誤消息會返回這個用戶 ID
 */
enum UserHandle : int32_t {
    NONE = -1
};

/**
 * 狀態(tài)碼
 */
enum Status : uint32_t {
    /**
     * 方法被成功調(diào)用
     */
    OK = 0,

    /**
     * 方法調(diào)用的參數(shù)之一無效
     */
    ILLEGAL_ARGUMENT = 1,

    /**
     * 人臉 HAL 不支持這個操作
     */
    OPERATION_NOT_SUPPORTED = 2,

    /**
     *  HAL 遭遇內(nèi)部錯誤湾笛,不能完成請求
     */
    INTERNAL_ERROR = 3,

    /**
     * 沒有錄入人臉
     */
    NOT_ENROLLED = 4
};

enum Feature : uint32_t {
    /**
     * 要求注視
     */
    REQUIRE_ATTENTION = 1,

    /**
     * 要求錄入時姿勢多樣(有變化) 
     */
    REQUIRE_DIVERSITY = 2
};

/**
 * onError 回調(diào)的人臉錯誤消息
 */
enum FaceError : int32_t {

    /**
     * 不能被解析的硬件錯誤
     */
    HW_UNAVAILABLE = 1,

    /**
     * 不能處理當(dāng)前操作
     */
    UNABLE_TO_PROCESS = 2,

    /**
     * 超時
     */
    TIMEOUT = 3,

    /**
     * 沒有足夠的存儲空間去完成當(dāng)前的操作
     */
    NO_SPACE = 4,

    /**
     * 被取消
     */
    CANCELED = 5,

    /**
     * 無法刪除
     */
    UNABLE_TO_REMOVE = 6,

    /**
     * 30s 禁用
     */
    LOCKOUT = 7,

    /**
     * 用來開啟供應(yīng)商指定的錯誤消息
     */
    VENDOR = 8,

    /**
     * 禁用直到使用主身份認(rèn)證
     */
    LOCKOUT_PERMANENT = 9
};

/**
 * 向客戶端反饋獲取人臉的消息(質(zhì)量)饮怯,以便用戶做出相應(yīng)的改變
 */
enum FaceAcquiredInfo : int32_t {

    GOOD = 0,

    /**
     * 無效人臉
     */
    INSUFFICIENT = 1,

    /**
     * 人臉太亮
     */
    TOO_BRIGHT = 2,

    /**
     * 人臉太暗
     */
    TOO_DARK = 3,

    /**
     * 人臉太近
     */
    TOO_CLOSE = 4,

    /**
     * 人臉太遠(yuǎn)
     */
    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,

    /**
     * 檢測到運(yùn)動過多
     */
    TOO_MUCH_MOTION = 12,

    /**
     * 重新校正
     */
    RECALIBRATE = 13,

    /**
     * 和前一幀差異太大
     */
    TOO_DIFFERENT = 14,

    /**
     * 和前一幀太相似
     */
    TOO_SIMILAR = 15,

    /**
     * 搖射角度太大,直面相機(jī)角度為 0
     */
    PAN_TOO_EXTREME = 16,

    /**
     * 傾斜角度太大
     */
    TILT_TOO_EXTREME = 17,

    /**
     * 側(cè)傾角幅度太大
     */
    ROLL_TOO_EXTREME = 18,

   /**
     * 人臉被遮擋
     */
    FACE_OBSCURED = 19,

    START = 20,

    /**
     * 傳感器(攝像頭)臟了
     */
    SENSOR_DIRTY = 21,

    /**
     * 用于開啟供應(yīng)商指定的獲取人臉的消息
     */
    VENDOR = 22
};

/**
 * 結(jié)果
 */
struct OptionalUint64 {
    /**
     * 返回的狀態(tài)
     */
    Status status;

    /**
     * 只意味著狀態(tài)是 OK 的
     */
    uint64_t value;
};

/**
 * 結(jié)果
 */
struct OptionalBool {
    /**
     * 返回的狀態(tài)
     */
    Status status;

    /**
     * 只意味著狀態(tài)是 OK 的
     */
    bool value;
};

人臉識別調(diào)用流程(注冊監(jiān)聽薛窥、捕獲人臉、比對)

人臉解鎖的入口在Keyguard中孤个,但要從

息屏的處理是從PowerManager開始论矾,最終到鎖屏的核心類KeyguardViewMediator教翩,息屏處理的大致流程如下:
息屏處理流程圖.png

前面幾步就跳過,直接從PhoneWindowManager開始分析贪壳。滅屏之后會調(diào)用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);
        }
    }

在該方法中又調(diào)用了KeyguardServiceDelegate類的onStartedGoingToSleep方法饱亿。

KeyguardServiceDelegate#onStartedGoingToSleep →KeyguardServiceWrapper#onStartedGoingToSleep → KeyguardService#onStartedGoingToSleep → KeyguardViewMediator#onStartedGoingToSleep,最終會調(diào)用到KeyguardViewMediator鎖屏核心類闰靴。

// KeyguardViewMediator.java
    public void onStartedGoingToSleep(int why) {
        if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + why + ")");
        synchronized (this) {
            mDeviceInteractive = false;
            mGoingToSleep = true;


            // 這位置的代碼作用具體不知彪笼,但放在前面可以解決息屏后又立馬使用指紋解鎖時:出現(xiàn)1.2s內(nèi)沒反應(yīng)的問題。
            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可以監(jiān)聽到GoingToSleep
        // KeyguardUpdateMonitor 是Keyguard更新監(jiān)視器
        mUpdateMonitor.dispatchStartedGoingToSleep(why);
        //通知開始息屏
        notifyStartedGoingToSleep();
    }

這里主要分析的是屏幕自己息屏蚂且,則重點關(guān)注mUpdateMonitor.dispatchStartedGoingToSleep(why)杰扫。

// KeyguardUpdateMonitor.java

    // 等待屏幕超時息屏,handler會發(fā)送 MSG_STARTED_GOING_TO_SLEEP
    public void dispatchStartedGoingToSleep(int why) {
        mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, 0));
    }


    // 注意:如果說按電源鍵息屏膘掰,handler會發(fā)送 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.Throwable
09-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.Throwable
09-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發(fā)送消息讓: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();
    }

在這篇文章里,我們只需要關(guān)注updateFaceListeningState()识埋,更新人臉狀態(tài)凡伊。

// KeyguardUpdateMonitor.java
    private void updateFaceListeningState() {
        // 如果此消息存在,我們不應(yīng)再次進(jìn)行身份驗證
        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) {
            // 在這里開始監(jiān)聽人臉
            /*重點關(guān)注*/
            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();
            /*重點關(guān)注*/
            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 {
            /*重點關(guān)注*/
            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");

                /*重點關(guān)注*/    
                // 進(jìn)行人臉認(rèn)證  
                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 */);
             /*重點關(guān)注*/
            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);
            /*重點關(guān)注*/
            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;
        }
        /*重點關(guān)注*/
        startClient(client, true /* initiatedByClient */);
        //這里將AuthenticationClient傳遞進(jìn)去
    }    


    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;
            /*重點關(guān)注*/
            startCurrentClient(mCurrentClient.getCookie());
            //這里繼續(xù)將AuthenticationClient傳遞進(jìn)去
        }
    }

    protected void startCurrentClient(int cookie) {
    
         // 省略部分代碼......

         /*重點關(guān)注*/
         //這里調(diào)用的是AuthenticationClient的start方法
        int status = mCurrentClient.start();

        if (status == 0) {
            notifyClientActiveCallbacks(true);
        }
      // ... ...
    }

mCurrentClient是ClientMonitor的對象系忙,而AuthenticationClient繼承了ClientMonitor類;
AuthenticationClient#start()

    // 開始驗證
    public int start() {
        mStarted = true;
        onStart();
        try {
            /*重點關(guān)注*/
            // 獲取 DaemonWrappe 對象開始鑒權(quán)惠豺,這里如果鑒權(quán)完成會回調(diào)注冊的 ClientMonito r的 onAuthenticated 接口
            //到這一步 DaemonWrappe 對象 進(jìn)入等待捕獲人臉信息银还,攝像頭會給到DaemonWrappe對象人臉信息。
            // 這里對調(diào)用到 DaemonWrapper 在 FaceService 里有實現(xiàn)洁墙,在那里會直接調(diào)用到 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方法會調(diào)用faced蛹疯,調(diào)用底層的人臉庫,底層庫返回結(jié)果后會調(diào)用onAuthenticated來反饋結(jié)果給receiver热监,在往上層反饋捺弦。

補(bǔ)充:IExtBiometricsFace.hal 這個接口在 ExtBiometricsFace.cpp中實現(xiàn)。

// 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");
    }

屏幕解鎖(結(jié)果回調(diào)、移除鎖)

底層庫回調(diào)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.Throwable
09-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)

根據(jù)前面的講的 底層 Face HIDL 可以知道 IExtBiometricsFaceClientCallback 是回調(diào)人臉識別結(jié)果的苦始。onAuthenticated()是當(dāng)一張人臉被成功認(rèn)證時被回調(diào)寞钥。

 // 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) 的調(diào)用。將會調(diào)用到:
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 的內(nèi)部類FaceServiceWrapper的authenticate()方法進(jìn)行實例化傳過去的蹄溉。反正最終將會回調(diào)到FaceService.java 的內(nèi)部類FaceAuthClient的onAuthenticated()方法

        @Override
        public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
                boolean authenticated, ArrayList<Byte> token) {
            Log.d("yexiao","yexiao:FaceAuthClient onAuthenticated ",new Throwable());
            
            // 重點關(guān)注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將會調(diào)到父類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()) {
                            /*重點關(guān)注*/ 
                            // getIsRestricted() 獲取有沒有權(quán)限登錄香浩,說白了就是驗證是否成功
                            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 接口的回調(diào),BiometricServiceBase的內(nèi)部類BiometricServiceListener也實現(xiàn)了該接口臼勉,但是沒有實現(xiàn)onAuthenticationSucceeded() 方法邻吭,而該ServiceListener 接口在FaceService中的內(nèi)部類ServiceListenerImpl 也有實現(xiàn),并且實現(xiàn)了onAuthenticationSucceeded() 方法宴霸。所以將會回調(diào)到FaceService內(nèi)部類的 ServiceListenerImpl#onAuthenticationSucceeded()囱晴。
ServiceListenerImpl#onAuthenticationSucceeded()

    /**
     * 從 ClientMonitor 實現(xiàn)接收回調(diào)。結(jié)果被轉(zhuǎn)發(fā)到 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) {

                    // 重點關(guān)注這里
                    mFaceServiceReceiver.onAuthenticationSucceeded(deviceId, (Face) biometric,
                            userId, isStrongBiometric());
                } else {
                    Slog.e(TAG, "onAuthenticationSucceeded received non-face biometric");
                }
            }
        }

         // 省略部分代碼 ......
    }

ServiceListenerImpl 這個類是負(fù)責(zé)將回調(diào)結(jié)果瓢谢,轉(zhuǎn)發(fā)到 FaceManager 中的畸写。通過 IFaceServiceReceiver 的對象,回調(diào) 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 發(fā)送了 MSG_AUTHENTICATION_SUCCEEDED 消息枯芬,在 handleMessage 中將會執(zhí)行 sendAuthenticatedSucceeded() 方法。

 // FaceManager.java
    private void sendAuthenticatedSucceeded(Face face, int userId, boolean isStrongBiometric) {
        if (mAuthenticationCallback != null) {
            final AuthenticationResult result =
                    new AuthenticationResult(mCryptoObject, face, userId, isStrongBiometric);
            
            // 主要關(guān)注這里
            mAuthenticationCallback.onAuthenticationSucceeded(result); 

            mAuthenticationCallback = null;
            if(mPendingFaceAuth != null) {
                authenticateInternel(mPendingFaceAuth.mCrypto, mPendingFaceAuth.mCancel, mPendingFaceAuth.mFlags, mPendingFaceAuth.mCallback, mPendingFaceAuth.mHandler, mPendingFaceAuth.mUserId);
                mPendingFaceAuth = null;
            }
        }
    }

在 sendAuthenticatedSucceeded() 方法中將會執(zhí)行 BiometricAuthenticator.AuthenticationCallback 的接口的回調(diào)采郎,將會把結(jié)果回調(diào)到 KeyguardUpdateMonitor 中FaceManager.AuthenticationCallback 的onAuthenticationSucceeded() 方法千所。
FaceManager.AuthenticationCallback#onAuthenticationSucceeded()
可以看一個堆棧圖:

09-13 16:33:50.024  1414  1414 D yexiao  : java.lang.Throwable
09-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");
            // 重點關(guān)注
            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;
            }
            /*重點關(guān)注*/
            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++) {
            /*重點關(guān)注*/
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
                /*重點關(guān)注*/
                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();
    }

這里開始調(diào)用接口將解鎖成功消息層層傳遞直至keyguard解鎖,與指紋解鎖邏輯一致

可以看到在 onFaceAuthenticated(userId) 方法中調(diào)用了 KeyguardUpdateMonitorCallback 這個抽象類的 onBiometricAuthenticated() 抽象方法蒜埋,而 BiometricUnlockController extends KeyguardUpdateMonitorCallback淫痰,并且注冊了回調(diào) mUpdateMonitor.registerCallback(this)。

BiometricUnlockController #onBiometricAuthenticated()

// BiometricUnlockController.java
    @Override
    public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
            boolean isStrongBiometric) {

        // 省略部分代碼......

        if (unlockAllowed) {
            mKeyguardViewMediator.userActivity();
            /*重點關(guān)注*/
            // 開始喚醒和解鎖
            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) {
               /*重點關(guān)注*/
                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;
        /*重點關(guān)注*/
        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);
        /*重點關(guān)注*/
        Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
        mHandler.sendMessage(msg);
        Trace.endSection();
    }

keyguardDone()該方法發(fā)送了一條 KEYGUARD_DONE 消息整份,在 handleMessage 中將會執(zhí)行 handleKeyguardDone() 方法待错。

KeyguardViewMediator#handleKeyguardDone()

// KeyguardViewMediator.java
    private void handleKeyguardDone() {
        Trace.beginSection("KeyguardViewMediator#handleKeyguardDone");
        final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
        // 省略部分代碼......

        /*
         * 重點關(guān)注
         * 處理隱藏
        **/
        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 {
                /*重點關(guān)注*/
                // 處理開始鍵盤保護(hù)退出動畫
                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();

            /*重點關(guān)注*/
            mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
            resetKeyguardDonePendingLocked();
            mHideAnimationRun = false;
            adjustStatusBarLocked();
            sendUserPresentBroadcast();
        }
        Trace.endSection();
    }

下面就不詳細(xì)分析了,將會按如下順序執(zhí)行:StatusBarKeyguardViewManager#hide()→StatusBarKeyguardViewManager#hideBouncer()→KeyguardBouncer#hide()→KeyguardBouncer#mRemoveViewRunnable→KeyguardBouncer#removeView()烈评。

至此鎖屏界面移除的邏輯基本clear

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末火俄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子讲冠,更是在濱河造成了極大的恐慌烛占,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沟启,死亡現(xiàn)場離奇詭異忆家,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)德迹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門芽卿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胳搞,你說我怎么就攤上這事卸例〕蒲睿” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵筷转,是天一觀的道長姑原。 經(jīng)常有香客問我,道長呜舒,這世上最難降的妖魔是什么锭汛? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮袭蝗,結(jié)果婚禮上唤殴,老公的妹妹穿的比我還像新娘。我一直安慰自己到腥,他們只是感情好朵逝,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乡范,像睡著了一般配名。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晋辆,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天段誊,我揣著相機(jī)與錄音,去河邊找鬼栈拖。 笑死连舍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涩哟。 我是一名探鬼主播索赏,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼贴彼!你這毒婦竟也來了潜腻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤器仗,失蹤者是張志新(化名)和其女友劉穎融涣,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體精钮,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡威鹿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了轨香。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忽你。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖臂容,靈堂內(nèi)的尸體忽然破棺而出科雳,到底是詐尸還是另有隱情根蟹,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布糟秘,位于F島的核電站简逮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏尿赚。R本人自食惡果不足惜散庶,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吼畏。 院中可真熱鬧督赤,春花似錦嘁灯、人聲如沸泻蚊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽性雄。三九已至,卻和暖如春羹奉,著一層夾襖步出監(jiān)牢的瞬間秒旋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工诀拭, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留迁筛,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓耕挨,卻偏偏與公主長得像细卧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筒占,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容