學(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教翩,息屏處理的大致流程如下:前面幾步就跳過,直接從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