Android N指紋識別
第一部分 指紋模組流程分析
一、Fingerprint模組架構
Fingerprint模組架構圖如下,這裡分為application,framework,fingerprintd和FingerprintHal這幾個部分,不涉及指紋的IC庫和驅動這部分,這部分邏輯由指紋廠商來實現。
Setting中指紋程式碼
SystemUI中指紋解鎖程式碼
二、Fingerprint framework初始化流程
在系統開機的時候,會啟動各種Service,包括FingerprintService。從下圖的開機log(sys_log.boot)中可以看出:
05-29 10:37:57.870869 1127 1127 I SystemServiceManager: Starting com.android.server.dreams.DreamManagerService 05-29 10:37:57.874643 1127 1127 I SystemServer: StartAssetAtlasService 05-29 10:37:57.883240 1127 1127 I SystemServiceManager: Starting com.android.server.print.PrintManagerService 05-29 10:37:57.910104 1127 1127 I SystemServiceManager: Starting com.android.server.restrictions.RestrictionsManagerService 05-29 10:37:57.913926 1127 1127 I SystemServiceManager: Starting com.android.server.media.MediaSessionService 05-29 10:37:57.926584 1127 1127 I SystemServer: StartMediaRouterService 05-29 10:37:57.939619 1127 1127 I SystemServiceManager: Starting com.android.server.trust.TrustManagerService 05-29 10:37:57.952689 1127 1127 I SystemServiceManager: Starting com.android.server.fingerprint.FingerprintService 05-29 10:37:58.866228 1127 1127 V FingerprintService: Fingerprint HAL id: 488345235968 05-29 10:37:58.867305 1127 1127 I SystemServer: StartBackgroundDexOptService
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
FingerprintService的啟動在SystemServer.Java的startOtherService方法中
/** * Starts a miscellaneous grab bag of stuff that has yet to be refactored * and organized. */ private void startOtherServices() { final Context context = mSystemContext; VibratorService vibrator = null; IMountService mountService = null; ....... //啟動FingerprintService if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { mSystemServiceManager.startService(FingerprintService.class); } ......
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
這裡啟動的時候,會將FingerprintService新增到ServiceManager中去,如下圖:
將FingerprintService新增到ServiceManager中後,在SystemServiceRegistry.java中靜態程式碼塊中註冊服務的時候,可以從ServiceManager中獲取FingerprintService的Binder物件,從而可以構造出FingerprintManager物件,這樣app端就可以通過Context來獲取FingerprintManager物件。另外FingerprintService的onStart()方法中還會呼叫getFingerprintDaemon()來完成以下步驟:
//①獲取fingerprintd
//②向fingerprintd註冊回撥函式mDaemonCallback
//③呼叫獲取fingerprintd的openhal函式
public IFingerprintDaemon getFingerprintDaemon() {
//①獲取fingerprintd
mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(
FINGERPRINTD));
mDaemon.asBinder().linkToDeath(this, 0);
//②向fingerprintd註冊回撥函式mDaemonCallback
mDaemon.init(mDaemonCallback);
//③呼叫獲取fingerprintd的openhal函式
mHalDeviceId = mDaemon.openHal();
......
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
app端通過Context獲取FingerprintManager,通過呼叫FingerprintManager的介面來實現相應的功能,FingerprintManager轉調FingerprintService中方法,FingerprintService負責管理整個註冊,識別、刪除指紋、檢查許可權等流程的邏輯,FingerprintService呼叫fingerprintd的介面,通過fingerprintd和FingerprintHal層進行通訊。
三、fingerprintd
fingerprintd在system/core/fingerprintd目錄下
fingerprintd可以分為四個部分:
1. fingerprintd.cpp “負責將fingerprintd加入到ServiceManager中,以便FingerprintService能夠獲取”
2. IFingerprintDaemon.h/IFingerprintDaemon.cpp “負責java層到fingerprintd的Binder通訊(我們指紋錄入和識別都會呼叫裡面的方法)”
3. FingerprintDaemonProxy.h/FingerprintDaemonProxy.cpp “負責fingerprintd和Fignerprint hal層的通訊”
4. IFingerprintDaemonCallback.h/IFingerprintDaemonCallback.cpp “負責將指紋的回撥結果傳給java層”
四、指紋錄製流程
指紋錄製的activity為FingerprintEnrollEnrolling實現了FingerprintEnrollSidecar.Listener 介面。
//指紋錄製時提示(比如太快,移動手指之類)
@Override
public void onEnrollmentHelp(CharSequence helpString) {
mErrorText.setText(helpString);
}
//提示指紋錄製過程中超時,或者未註冊。
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
int msgId;
......
showErrorDialog(getText(msgId), errMsgId);
......
}
//錄製過程中進度的變化
@Override
public void onEnrollmentProgressChange(int steps, int remaining) {
updateProgress(true /* animate */);//更新進度
updateDescription();//更新描述
animateFlash();//更新動畫
......
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
FingerprintEnrollSidecar的onStart方法中呼叫了startEnrollment(),該方法中呼叫FingeprintManager的enroll方法,並且傳入了EnrollmentCallback物件,EnrollmentCallback是指紋錄入結果的回撥,分別呼叫了FingerprintEnrollSidecar.Listener 介面中的方法,這樣就能更新指紋錄製的進度和錄製結果。
private void startEnrollment() {
......
mFingerprintManager.enroll(mToken, mEnrollmentCancel,
0 /* flags */, mUserId, mEnrollmentCallback);
mEnrolling = true;
}
private FingerprintManager.EnrollmentCallback mEnrollmentCallback
= new FingerprintManager.EnrollmentCallback() {
@Override
public void onEnrollmentProgress(int remaining) {
......
mListener.onEnrollmentProgressChange(mEnrollmentSteps, remaining);
}
}
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (mListener != null) {
mListener.onEnrollmentHelp(helpString);
}
}
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mListener != null) {
mListener.onEnrollmentError(errMsgId, errString);
}
mEnrolling = false;
}
};
public void enroll(byte [] token, CancellationSignal cancel, int flags,
int userId, EnrollmentCallback callback) {
......
mService.enroll(mToken, token, userId, mServiceReceiver, flags,
mContext.getOpPackageName());
......
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
注意傳入的mServiceReceiver物件,這個物件會通過handler傳送相關訊息去呼叫EnrollmentCallback或者AuthenticationCallback中方法。
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@Override // binder call
public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
}
@Override // binder call
public void onAcquired(long deviceId, int acquireInfo) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
}
@Override // binder call
public void onAuthenticationSucceeded(long deviceId, Fingerprint fp, int userId) {
mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, 0, fp).sendToTarget();
}
@Override // binder call
public void onAuthenticationFailed(long deviceId) {
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();;
}
@Override // binder call
public void onError(long deviceId, int error) {
mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
}
@Override // binder call
public void onRemoved(long deviceId, int fingerId, int groupId) {
mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
}
};
public void handleMessage(android.os.Message msg) {
switch(msg.what) {
case MSG_ENROLL_RESULT:
sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
break;
case MSG_ACQUIRED:
sendAcquiredResult((Long) msg.obj /* deviceId */,
msg.arg1 /* acquire info */);
break;
case MSG_AUTHENTICATION_SUCCEEDED:
sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
break;
case MSG_AUTHENTICATION_FAILED:
sendAuthenticatedFailed();
break;
case MSG_ERROR:
sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
break;
case MSG_REMOVED:
sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
msg.arg2 /* groupId */);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
FingerprintManager與FingerprintService直接通過aidl進行通訊,在FingerprintService中內部類FingerprintServiceWrapper實現了IFingerprintService.Stub,我們呼叫的FingerManger的enroll方法就是呼叫FingerprintServiceWrapper類中的enroll()。
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
......
@Override // Binder call
public void enroll(final IBinder token, final byte[] cryptoToken,
final int userId,final IFingerprintServiceReceiver receiver,
final int flags,
final String opPackageName) {
checkPermission(MANAGE_FINGERPRINT);
final int limit = mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
final int enrolled = FingerprintService.this.
getEnrolledFingerprints(userId).size();
if (enrolled >= limit) {
Slog.w(TAG, "Too many fingerprints registered");
return;
}
......
mHandler.post(new Runnable() {
@Override
public void run() {
startEnrollment(token, cryptoToken, userId, receiver,
flags,restricted, opPackageName);
}
});
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
startEnrollment方法中會呼叫EnrollClient的start方法,EnrollClient是為給定的客戶端跟蹤指紋錄製狀態。
/**
* A class to keep track of the enrollment state for a given client.
*/
public abstract class EnrollClient extends ClientMonitor {
......
public EnrollClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int userId, int groupId, byte [] cryptoToken,
boolean restricted, String owner) {
super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
......
}
@Override
public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
......
return sendEnrollResult(fingerId, groupId, remaining);
}
/*
* @return true if we're done.
*/
private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
IFingerprintServiceReceiver receiver = getReceiver();
......
receiver.onEnrollResult(getHalDeviceId(), fpId, groupId, remaining);
......
}
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
......
final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
......
return 0; // success
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
start方法會呼叫fingerprintd,呼叫底層的指紋庫,底層庫返回結果後會呼叫onEnrollResult來反饋結果給receiver,在往上層反饋。這就是指紋的錄製流程。
五、指紋的解鎖流程
指紋解鎖的核心類FingerprintUnlockController,實現了KeyguardUpdateMonitorCallback
public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
@Override
public void onFingerprintAuthenticated(int userId) {
......
switch (mMode) {
case MODE_DISMISS_BOUNCER://亮屏並且出現圖案鎖
mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
false /* strongAuth */);
break;
case MODE_UNLOCK://亮屏不出現圖案鎖
if (!wasDeviceInteractive) {
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
}
mStatusBarKeyguardViewManager.animateCollapsePanels(
FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
break;
......
case MODE_WAKE_AND_UNLOCK://息屏鎖屏解鎖
mStatusBarWindowManager.setStatusBarFocusable(false);
mDozeScrimController.abortPulsing();
mKeyguardViewMediator.onWakeAndUnlocking();
mScrimController.setWakeAndUnlocking();
if (mPhoneStatusBar.getNavigationBarView() != null) {
mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
}
break;
......
case MODE_DISMISS_KEYGUARD://通話介面息屏解鎖
mStatusBarWindowManager.setStatusBarFocusable(false);
mKeyguardViewMediator.onWakeAndUnlocking();
if (mPhoneStatusBar.getNavigationBarView() != null) {
mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
}
break;
}
......
}
@Override
public void onFinishedGoingToSleep(int why) {
......
}
@Override
public void onFingerprintAuthFailed() {
cleanup();
}
@Override
public void onFingerprintError(int msgId, String errString) {
cleanup();
if(Settings.Global.getInt(mContext.getContentResolver(),"persist.fg.errorshow",0) == 0){
if(!mPowerManager.isScreenOn()){
mPowerManager.wakeUp(SystemClock.uptimeMillis());
}else {
mStatusBarKeyguardViewManager.animateCollapsePanels(
FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
}
Settings.Global.putInt(mContext.getContentResolver(),"persist.fg.errorshow",1);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
KeyguardUpdateMonitor類為解鎖屏模組的監聽者,它負責監聽時間、sim卡、運營商資訊、電池資訊、電話資訊等狀態的變化,並通知keyguard View模組更新顯示。這個類裡面還有有監聽指紋的方法startListeningForFingerprint, 該方法呼叫了FingerprintManager的authenticate()方法並且引數中傳入了AuthenticationCallback物件,AuthenticationCallback類中呼叫了KeyguardUpdateMonitorCallback的方法,FingerprintUnlockController實現了KeyguardUpdateMonitorCallback這樣就能實現指紋解鎖。
private void startListeningForFingerprint() {
......
//呼叫了FingerprintManager的authenticate()方法
mFpm.authenticate(null, mFingerprintCancelSignal, 0,
mAuthenticationCallback, null, userId);
......
}
private FingerprintManager.AuthenticationCallback mAuthenticationCallback
= new AuthenticationCallback() {
//指紋匹配失敗(沒超過5次)
@Override
public void onAuthenticationFailed() {
handleFingerprintAuthFailed();
};
//指紋匹配成功
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
handleFingerprintAuthenticated(result.getUserId());
}
//指紋匹配提示
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
handleFingerprintHelp(helpMsgId, helpString.toString());
}
//指紋匹配錯誤(匹配失敗次數超過5次)
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
handleFingerprintError(errMsgId, errString.toString());
}
//獲得到指紋
@Override
public void onAuthenticationAcquired(int acquireInfo) {
if(Settings.Global.getInt(mContext.getContentResolver(),"persist.
fg.errorshow",0) == 1){
Settings.Global.putInt(mContext.getContentResolver(),"persist
.fg.errorshow",0);
}
handleFingerprintAcquired(acquireInfo);
}
};
private void handleFingerprintAuthenticated(int authUserId) {
......
onFingerprintAuthenticated(userId);
......
private void onFingerprintAuthenticated(int userId) {
mUserFingerprintAuthenticated.put(userId, true);
......
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
//這裡會呼叫FingerprintUnLockController中的onFingerprintAuthenticated方法處理解鎖
cb.onFingerprintAuthenticated(userId);
}
}
.....
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
回來繼續看FingerprintManager的authenticate()方法,此方法繼續呼叫了FingerprintServiceWarpper的authenticate方法(FingerprintManager與FingerprintService直接通過aidl來通訊)。
public void authenticate(@Nullable CryptoObject crypto, @Nullable
......
mService.authenticate(mToken, sessionId, userId, mServiceReceiver,
flags,mContext.getOpPackageName());
......
}
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
@Override // Binder call
public void authenticate(final IBinder token, final long opId,
final int groupId,final IFingerprintServiceReceiver receiver,
final int flags,final String opPackageName) {
startAuthentication(token, opId, callingUserId, groupId,
receiver, flags, restricted, opPackageName);
}
startAuthentication方法會呼叫AuthenticationClient的start方法,AuthenticationClient
是為給定的客戶端跟蹤指紋認證狀態。
public abstract class AuthenticationClient extends ClientMonitor {
public AuthenticationClient(Context context, long halDeviceId, IBinder token,
IFingerprintServiceReceiver receiver, int targetUserId,
int groupId, long opId,boolean restricted, String owner) {
super(context, halDeviceId, token, receiver, targetUserId,
groupId, restricted, owner);
}
//指紋庫處理結果呼叫
@Override
public boolean onAuthenticated(int fingerId, int groupId) {
......
boolean authenticated = fingerId != 0;
if (!authenticated) {
//認證失敗
receiver.onAuthenticationFailed(getHalDeviceId());
} else {
//認證成功
receiver.onAuthenticationSucceeded(getHalDeviceId(), fp, getTargetUserId());
}
if (!authenticated) {
if (inLockoutMode) {
//認證錯誤
receiver.onError(getHalDeviceId(),
FingerprintManager.FINGERPRINT_ERROR_LOCKOUT);
}
}
......
}
/**
* Start authentication
*/
@Override
public int start() {
IFingerprintDaemon daemon = getFingerprintDaemon();
......
final int result = daemon.authenticate(mOpId, getGroupId());
......
return 0; // success
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
start方法會呼叫fingerprintd,呼叫底層的指紋庫,底層庫返回結果後會呼叫onAuthenticated來反饋結果給receiver,在往上層反饋。這就是指紋的識別流程。