Android7.0指紋服務(wù)FingerprintService實例介紹
指紋服務(wù)是Android系統(tǒng)中一個較為簡單的服務(wù)(相比于AMS,WMS等),也比較獨立,功能上包括幾點
- 指紋的錄入與刪除
- 指紋認證
- 指紋的安全策略(錯誤次數(shù)判定)
和其他的system service 一樣,應(yīng)用程序通過FingerprintManager實現(xiàn)與FingerprintService的通信,除了上面所說的功能之外,F(xiàn)ingerprintManager提供了一些別的的接口,重要的接口都會要求系統(tǒng)級別的權(quán)限,并且也不是公開的api(指紋的錄入,刪除,重命名,重置錯誤計數(shù)等)
/** * Obtain the list of enrolled fingerprints templates. * @return list of current fingerprint items * * @hide */ @RequiresPermission(USE_FINGERPRINT) public List<Fingerprint> getEnrolledFingerprints(int userId) { if (mService != null) try { return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return null; } /** * @hide */ @RequiresPermission(allOf = { USE_FINGERPRINT, INTERACT_ACROSS_USERS}) public boolean hasEnrolledFingerprints(int userId) { if (mService != null) try { return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return false; } /** * Determine if fingerprint hardware is present and functional. * * @return true if hardware is present and functional, false otherwise. */ @RequiresPermission(USE_FINGERPRINT) public boolean isHardwareDetected() { if (mService != null) { try { long deviceId = 0; /* TODO: plumb hardware id to FPMS */ return mService.isHardwareDetected(deviceId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!"); } return false; }
FingerprintService的啟動過程
FingerprintService在system server中創(chuàng)建并初始化,當檢測到手機支持指紋功能的時候就會啟動這個service
... if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { mSystemServiceManager.startService(FingerprintService.class); } ...
FingerprintService在初始化后會建立和HAL層的通信,即連接到fingerprintd,拿到用于通信的IFingerprintDaemon對象(binder)
public void onStart() { publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); IFingerprintDaemon daemon = getFingerprintDaemon(); listenForUserSwitches(); } public IFingerprintDaemon getFingerprintDaemon() { if (mDaemon == null) { mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD)); if (mDaemon != null) { try { mDaemon.asBinder().linkToDeath(this, 0); mDaemon.init(mDaemonCallback); mHalDeviceId = mDaemon.openHal(); if (mHalDeviceId != 0) { updateActiveGroup(ActivityManager.getCurrentUser(), null); } else { Slog.w(TAG, "Failed to open Fingerprint HAL!"); MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1); mDaemon = null; } } catch (RemoteException e) { Slog.e(TAG, "Failed to open fingeprintd HAL", e); mDaemon = null; // try again later! } } else { Slog.w(TAG, "fingerprint service not available"); } } return mDaemon; }
本質(zhì)上來說,除去安全相關(guān)的策略外,指紋的功能是依賴硬件實現(xiàn)的,F(xiàn)ingerprintService也只是充當了framework java層與native層的消息傳遞者罷了,所以指紋的識別,錄入和監(jiān)聽都是向fingerprintd發(fā)送命令和獲取相應(yīng)的結(jié)果
指紋監(jiān)聽認證過程
以指紋認證為例,介紹這一過程,錄入和刪除的過程和認證類似,不重復(fù)描述
FingerprintManager
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } if (cancel != null) { if (cancel.isCanceled()) { Log.w(TAG, "authentication already canceled"); return; } else { cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto)); } } if (mService != null) try { useHandler(handler); mAuthenticationCallback = callback; mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags, mContext.getOpPackageName()); } catch (RemoteException e) { Log.w(TAG, "Remote exception while authenticating: ", e); if (callback != null) { // Though this may not be a hardware issue, it will cause apps to give up or try // again later. callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE, getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE)); } } }
可以看到,最終仍然是向FingerprintService發(fā)送消息,但是開啟指紋認證的函數(shù)傳入了兩個比較重要的參數(shù),一個是CancellationSignal對象,用于取消指紋認證,另一個是指紋認證的回調(diào)對象AuthenticationCallback
public static abstract class AuthenticationCallback { public void onAuthenticationError(int errorCode, CharSequence errString) { } public void onAuthenticationHelp(int helpCode, CharSequence helpString) { } public void onAuthenticationSucceeded(AuthenticationResult result) { } public void onAuthenticationFailed() { } public void onAuthenticationAcquired(int acquireInfo) {} };
看函數(shù)名稱也能知道其功能,他們分別代表了指紋認證時的回調(diào)結(jié)果(成功,失敗,檢測到指紋,認證異常等),參數(shù)包含了具體的信息,這些信息在FingerprintManager中都有對應(yīng)的常量定義,有興趣可以查看代碼
FingerprintService
public void authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getCallingUserId(); final int pid = Binder.getCallingPid(); final boolean restricted = isRestricted(); mHandler.post(new Runnable() { @Override public void run() { if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, callingUid, pid)) { if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName); return; } MetricsLogger.histogram(mContext, "fingerprint_token", 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; startAuthentication(token, opId, callingUserId, groupId, receiver, flags, restricted, opPackageName); } }); }
前面會有對包名,userid以及應(yīng)用進程是否在在前臺的檢查,繼續(xù)看
private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName) { updateActiveGroup(groupId, opPackageName); if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")"); AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token, receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) { @Override public boolean handleFailedAttempt() { mFailedAttempts++; if (mFailedAttempts == MAX_FAILED_ATTEMPTS) { mPerformanceStats.lockout++; } if (inLockoutMode()) { // Failing multiple times will continue to push out the lockout time. scheduleLockoutReset(); return true; } return false; } @Override public void resetFailedAttempts() { FingerprintService.this.resetFailedAttempts(); } @Override public void notifyUserActivity() { FingerprintService.this.userActivity(); } @Override public IFingerprintDaemon getFingerprintDaemon() { return FingerprintService.this.getFingerprintDaemon(); } }; if (inLockoutMode()) { Slog.v(TAG, "In lockout mode; disallowing authentication"); // Don't bother starting the client. Just send the error message. if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { Slog.w(TAG, "Cannot send timeout message to client"); } return; } startClient(client, true /* initiatedByClient */); }
AuthenticationClient繼承自ClientMonitor,用于處理指紋認證相關(guān)的功能事務(wù),ClientMonitor的其他子類如RemovalMonior,EnrollMonitor也是如此,ClientMonitor會直接與fingerprintd通信,其核心是調(diào)用其start()或stop()方法,
對于AuthenticationClient而言
private void startClient(ClientMonitor newClient, boolean initiatedByClient) { ClientMonitor currentClient = mCurrentClient; if (currentClient != null) { if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString()); currentClient.stop(initiatedByClient); mPendingClient = newClient; mHandler.removeCallbacks(mResetClientState); mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT); } else if (newClient != null) { mCurrentClient = newClient; if (DEBUG) Slog.v(TAG, "starting client " + newClient.getClass().getSuperclass().getSimpleName() + "(" + newClient.getOwnerString() + ")" + ", initiatedByClient = " + initiatedByClient + ")"); newClient.start(); } } public int start() { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "start authentication: no fingeprintd!"); return ERROR_ESRCH; } try { final int result = daemon.authenticate(mOpId, getGroupId()); if (result != 0) { Slog.w(TAG, "startAuthentication failed, result=" + result); MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result); onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); return result; } if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating..."); } catch (RemoteException e) { Slog.e(TAG, "startAuthentication failed", e); return ERROR_ESRCH; } return 0; // success }
向底層發(fā)送認證命令后就只需要等待認證結(jié)果就可以了,前面我們說到在初始化的時候會建立與fingerprintd的通信,其核心是下面這行代碼
mDaemon.init(mDaemonCallback);
mDaemonCallback是一個binder對象,接受來自底層的結(jié)果,然后通過FingerprintService和FingerManager一層層把結(jié)果發(fā)送到應(yīng)用程序中去。
8.0的一些變化
8.0上的fingerprintd變化很大,甚至都不叫fingerprintd了,當然這是native層的東西,這里不討論,對于FingerprintService而言,一個顯著的變化是安全策略的調(diào)整
- 8.0之前,指紋只能錯誤5次,達到5次時會禁止指紋認證,同時開啟30秒倒計時,等待結(jié)束后重置錯誤計數(shù),繼續(xù)認證
- 8.0之后,依然是每錯誤5次就會倒計時30秒,然而30秒結(jié)束后錯誤計數(shù)并不會被清空,8.0上加入了最大20次的限制,累計錯誤20次之后就無法使用指紋認證功能了,只能用密碼的方式才能重置錯誤計數(shù)
private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5; private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20; private int getLockoutMode() { if (mFailedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) { return AuthenticationClient.LOCKOUT_PERMANENT; } else if (mFailedAttempts > 0 && mTimedLockoutCleared == false && (mFailedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) { return AuthenticationClient.LOCKOUT_TIMED; } return AuthenticationClient.LOCKOUT_NONE; }
總結(jié)
以上所述是小編給大家介紹的Android7.0指紋服務(wù)FingerprintService實例介紹,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android控件RecyclerView實現(xiàn)混排效果仿網(wǎng)易云音樂
這篇文章主要為大家詳細介紹了Android控件RecyclerView實現(xiàn)混排效果,仿網(wǎng)易云音樂,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10android開發(fā)教程之handle實現(xiàn)多線程和異步處理
這篇文章主要介紹了android的handle實現(xiàn)多線程和異步處理的示例,大家參考使用吧2014-01-01Android使用ViewFlipper實現(xiàn)圖片上下自動輪播的示例代碼
這篇文章主要介紹了Android使用ViewFlipper實現(xiàn)圖片上下自動輪播的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2021-05-05