手指在指紋傳感器上摸一下就能解鎖,Keyguard是怎麼作到的呢?java
下面咱們就跟着源碼,解析這整個過程。android
先來看下IKeyguardService這個binder接口有哪些回調吧併發
// 當另外一個窗口使用FLAG_SHOW_ON_LOCK_SCREEN解除Keyguard時PhoneWindowManager調用 public void setOccluded(boolean isOccluded, boolean animate) throws android.os.RemoteException; // 添加鎖屏狀態回調 public void addStateMonitorCallback(com.android.internal.policy.IKeyguardStateCallback callback) throws android.os.RemoteException; // 覈驗解鎖(用於快捷啓動) public void verifyUnlock(com.android.internal.policy.IKeyguardExitCallback callback) throws android.os.RemoteException; // 解除鎖屏 public void dismiss(com.android.internal.policy.IKeyguardDismissCallback callback) throws android.os.RemoteException; // 屏保開始(Intent.ACTION_DREAMING_STARTED) public void onDreamingStarted() throws android.os.RemoteException; // 屏保結束(Intent.ACTION_DREAMING_STOPPED) public void onDreamingStopped() throws android.os.RemoteException; // 設備開始休眠 reason:OFF_BECAUSE_OF_USER/OFF_BECAUSE_OF_ADMIN/OFF_BECAUSE_OF_TIMEOUT public void onStartedGoingToSleep(int reason) throws android.os.RemoteException; // 休眠完成 public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) throws android.os.RemoteException; // 設備開始喚醒 public void onStartedWakingUp() throws android.os.RemoteException; // 喚醒完成 public void onFinishedWakingUp() throws android.os.RemoteException; // 正在亮屏 public void onScreenTurningOn(com.android.internal.policy.IKeyguardDrawnCallback callback) throws android.os.RemoteException; // 已經亮屏完成 public void onScreenTurnedOn() throws android.os.RemoteException; // 正在滅屏 public void onScreenTurningOff() throws android.os.RemoteException; // 滅屏完成 public void onScreenTurnedOff() throws android.os.RemoteException; // 外部應用取消Keyguard接口 public void setKeyguardEnabled(boolean enabled) throws android.os.RemoteException; // 開機系統準備完成回調 public void onSystemReady() throws android.os.RemoteException; // 延時鎖屏 (用於自動休眠) public void doKeyguardTimeout(android.os.Bundle options) throws android.os.RemoteException; // 切換用戶中 public void setSwitchingUser(boolean switching) throws android.os.RemoteException; // 設置當前用戶 public void setCurrentUser(int userId) throws android.os.RemoteException; // 系統啓動完成回調 public void onBootCompleted() throws android.os.RemoteException; // Keyguard後面的activity已經繪製完成,能夠開始移除壁紙和Keyguard flag public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) throws android.os.RemoteException; // 通知Keyguard對power鍵作特殊處理,使設備不進行休眠或喚醒而是啓動Home(目前是空實現) public void onShortPowerPressedGoHome() throws android.os.RemoteException;
在這麼多接口裏,有
onStartedGoingToSleep/
onFinishedGoingToSleep/
onScreenTurningOff/
onScreenTurnedOff
這四個接口是在power鍵按下後觸發,其中onStartedGoingToSleep最早被觸發,他們的
調用順序我會在後文裏講解。ide
而咱們的指紋傳感器監聽,就是在onStartedGoingToSleep時開始的。
代碼邏輯由在KeyguardService中由中間類KeyguardMediator調用到KeyguardUpdateMonitor
android/frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.javapost
protected void handleStartedGoingToSleep(int arg1) { ... updateFingerprintListeningState(); } private void updateFingerprintListeningState() { // If this message exists, we should not authenticate again until this message is // consumed by the handler if (mHandler.hasMessages(MSG_FINGERPRINT_AUTHENTICATION_CONTINUE)) { return; } mHandler.removeCallbacks(mRetryFingerprintAuthentication); boolean shouldListenForFingerprint = shouldListenForFingerprint(); if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING && !shouldListenForFingerprint) { stopListeningForFingerprint(); } else if (mFingerprintRunningState != FINGERPRINT_STATE_RUNNING && shouldListenForFingerprint) { startListeningForFingerprint(); } }
在同時判斷mFingerprintRunningState和shouldListenForFingerprint後,
Keyguard在startListeningForFingerprint中真正使用FingerprintManager監聽指紋傳感器ui
private void startListeningForFingerprint() { if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING) { setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING_RESTARTING); return; } if (DEBUG) Log.v(TAG, "startListeningForFingerprint()"); int userId = ActivityManager.getCurrentUser(); if (isUnlockWithFingerprintPossible(userId)) { if (mFingerprintCancelSignal != null) { mFingerprintCancelSignal.cancel(); } mFingerprintCancelSignal = new CancellationSignal(); mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId); setFingerprintRunningState(FINGERPRINT_STATE_RUNNING); } }
真正到了使用指紋識別功能的時候,你會發現其實很簡單,只是調用 FingerprintManager 類的的方法authenticate()而已,而後系統會有相應的回調反饋給咱們,該方法以下:this
public void authenticate(CryptoObject crypto, CancellationSignal cancel, int flags, AuthenticationCallback callback, Handler handler, int userId)加密
該方法的幾個參數解釋以下:spa
下面只須要在mAuthenticationCallback繼承AuthenticationCallback這個抽象方法,重寫回調接口code
private FingerprintManager.AuthenticationCallback mAuthenticationCallback = new AuthenticationCallback() { @Override public void onAuthenticationFailed() { handleFingerprintAuthFailed(); }; @Override public void onAuthenticationSucceeded(AuthenticationResult result) { Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded"); handleFingerprintAuthenticated(result.getUserId()); Trace.endSection(); } @Override // 指紋驗證 public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { handleFingerprintHelp(helpMsgId, helpString.toString()); } @Override // 指紋驗證時回調 public void onAuthenticationError(int errMsgId, CharSequence errString) { } @Override // 獲取到指紋時回調 public void onAuthenticationAcquired(int acquireInfo) { handleFingerprintAcquired(acquireInfo); } };
從AuthenticationCallback裏能夠看出,獲取指紋回調首先發生在 onAuthenticationAcquired 中, 咱們先看代碼
private void handleFingerprintAcquired(int acquireInfo) { if (acquireInfo != FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) { return; } for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { cb.onFingerprintAcquired(); } } }
首先用acquireInfo參數判斷是否正確獲取指紋,以後遍歷KeyguardUpdateMonitorCallback,進行回調。
重寫onFingerprintAcquired方法的只有FingerprintUnlockController,FingerprintUnlockController就是
用於協調UI的全部指紋解鎖操做的控制器。
@Override public void onFingerprintAcquired() { ... mWakeLock = mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME); mWakeLock.acquire(); mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable, FINGERPRINT_WAKELOCK_TIMEOUT_MS); } ... }
onFingerprintAcquired的核心邏輯所有是和WakeLock相關的,
獲取WakeLock,併發送一條延時消息,15秒後,釋放WakeLock。
下一步就發生在,onFingerprintAuthenticated回調中了,實現onFingerprintAuthenticated接口的不止一處,但真正實現解鎖的仍是在FingerprintUnlockController中
@Override public void onFingerprintAuthenticated(int userId) { ... startWakeAndUnlock(calculateMode()); } private int calculateMode() { boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed(); boolean deviceDreaming = mUpdateMonitor.isDreaming(); if (!mUpdateMonitor.isDeviceInteractive()) { if (!mStatusBarKeyguardViewManager.isShowing()) { return MODE_ONLY_WAKE; } else if (mDozeScrimController.isPulsing() && unlockingAllowed) { return MODE_WAKE_AND_UNLOCK_PULSING; } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) { return MODE_WAKE_AND_UNLOCK; } else { return MODE_SHOW_BOUNCER; } } if (unlockingAllowed && deviceDreaming) { return MODE_WAKE_AND_UNLOCK_FROM_DREAM; } if (mStatusBarKeyguardViewManager.isShowing()) { if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) { return MODE_DISMISS_BOUNCER; } else if (unlockingAllowed) { return MODE_UNLOCK; } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) { return MODE_SHOW_BOUNCER; } } return MODE_NONE; }
這段代碼邏輯很清晰,就是根據鎖屏的狀態計算指紋解鎖的模式
public void startWakeAndUnlock(int mode) { ... boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive(); mMode = mode; if (!wasDeviceInteractive) { mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT"); } releaseFingerprintWakeLock(); switch (mMode) { ... } }
startWakeAndUnlock中的代碼通過簡化後,只剩三部分:
1.先判斷設備喚醒狀態,是用PowerManager的wakeUp接口點亮屏幕
2.而後釋放在acquire階段獲取的WakeLock
3.最後在根據上面calculateMode得出的解鎖模式,進行真正的解鎖動做,這在以前的解鎖流程中已經分析過,這裏再也不作分析。
這裏面值得咱們注意的是wakeUp接口, 下面咱們稍微對該接口進行一點探究
咱們知道上層應用要喚醒系統通常只能依靠兩種方式:
1.在應用啓動Activity時候設置相應的window的flags,經過WMS來喚醒系統;
即經過WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
2.在應用申請wakelock鎖時附帶ACQUIRE_CAUSES_WAKEUP標誌
PowerManager的wakeup接口屬性是@hide的,對通常應用是不可見的,而咱們的SystemUI就不存在調用問題。
SystemUI經過調用第三種方式:PowerManager的wakeup接口,來強制喚醒系統,若是該設備處於睡眠狀態,調用該接口會當即喚醒系統,好比按Power鍵,來電,鬧鐘等場景都會調用該接口。喚醒系統須要android.Manifest.permission#DEVICE_POWER的權限,咱們能夠看到SystemUI的Manifest文件裏已經添加了該權限。
PowerManagerService喚醒的流程請看流程圖:
PMS的wakeUp流程
從流程能夠看到,亮屏流程能夠和KeyguardService中的回調對應上了。
其實指紋解鎖的本質是在KeyguardService收到從PMS到WMS的調用中,在StartedGoingToSleep時就開始使用FingerprintManager的authticate開始監聽感器,在FIngerManager驗證成功時,使用PowerManagerService點亮屏幕,進行解鎖流程。