Android Fingerprint Framework (2): FingerprintService

蔣承達 (Jazz)
7 min readJan 18, 2019

--

這個系列主要用來介紹 Android Framework 上有關 Fingerprint 功能的設計,希望能幫助大家了解原生架構的設計與減少相關工作人員追蹤的時間。對這個主題有興趣的朋友可以從第一篇開始看,會比較接近 APP 的使用情境。
上次我們講到了如何從 FingerprintManager 呼叫到 FingerprintService,今天就來介紹 FingerprintService,主要也是以 Enroll 流程做為範例。

FingerprintService 是位於:
/frameworks/base/services/core/java/com/android/server/
fingerprint/FingerprintService.java

在這個流程被呼叫到第一個方法就是 FingerprintServiceWrapper 裡的 enroll:

可以看到他先做了一些事情:

  1. 確認 Permission:在 FingerprintManager 裡標注的@RequiresPermission(MANAGE_FINGERPRINT) 就是在這裡檢查
  2. 確認註冊指紋上限:在 /frameworks/base/core/res/res/values/config.xml 裡面 config_fingerprintMaxTemplatesPerUser 寫明了每個用戶註冊指紋上限為 5 個指紋。
  3. 確認此 userId 是否與目前的使用者有關

確定了 enroll 的各種合法性之後,最後執行了startEnrollment:

在 startEnrollment 可以看到最主要做的事情就是創建一個 EnrollClient,然後把他代入 startClient 開始啟動。

EnrollClient:

那我們就來簡單的看一下 EnrollClient,他與 FingerprintService 位於同一目錄:
/frameworks/base/services/core/java/com/android/server/
fingerprint/EnrollClient.java

首先看到了 EnrollClient 繼承自 ClientMonitor,因此我們就再看一下 ClientMonitor,來幫助我們理解他:
/frameworks/base/services/core/java/com/android/server/
fingerprint/ClientMonitor.java

可以看到 ClientMonitor 的幾個重點:

  1. 繼承自 IBinder.DeathRecipient,如此就可以藉由 linkToDeath() 讓這個類別監控 IBinder 的生命周期。
  2. 是一個抽象類別,定義了許多狀態發生時使用的 callback 名稱:
    onEnrollResult (回報註冊結果)
    onAuthenticated (回報驗證結果)
    onRemoved (回報移除結果)
    onEnumerationResult (回報列舉結果)
  3. 也定義了抽象的 start 與 stop 方法,等待實作。

而 EnrollClient 主要的內容就是實作完有關 Enroll 部分的成果:

最主要就是實作了這三個部分:

  1. start

使用 getFingerprintDaemon() 取得 IBiometricsFingerprint daemon,再直接呼叫 daemon.enroll() 開始註冊指紋。
這裡的 IBiometricsFingerprint 就是 Android HIDL 所定義的 HAL Service 了,也就是藉由 IBiometricsFingerprint 我們就已經呼叫到比更底層的服務了喔。

2. stop

主要也是使用 getFingerprintDaemon() 取得 IBiometricsFingerprint,再直接呼叫 daemon.cancel();
用來取消現在的程序。

3. onEnrollResult

將呼叫 sendEnrollResult,利用 getReceiver() 取得 IFingerprintServiceReceiver receiver,再利用 receiver.onEnrollResult() 回傳了註冊的結果。

IFingerprintServiceReceiver:

所謂的 IFingerprintServiceReceiver 就是實作在 FingerprintManager 的 mServiceReceiver,在註冊程序中被一路帶了下來。

呼叫了 receiver.onEnrollResult() 就等於是一路回傳結果進 FingerprintManager 中了:

這時候 mServiceReceiver 再傳送了 message: MSG_ENROLL_RESULT

MSG_ENROLL_RESULT 被處理時又呼叫了 sendEnrollResult,sendEnrollResult 就直接使用了 mEnrollmentCallback。
所謂的 mEnrollmentCallback 就是上一篇提到的抽象類別 EnrollmentCallback,主要會由 APP 端實作,
而呼叫 mEnrollmentCallback.onEnrollmentProgress(remaining);
就等於將 Enroll 的結果成功回傳給 APP 了!

恩恩恩!十分的有道理!
但… 那又是誰呼叫了 EnrollClient 的 onEnrollResult?

IBiometricsFingerprintClientCallback:

讓我們看到 FingerprintService 裡面的 getFingerprintDaemon:

在這個 Function 裡面除了 IBiometricsFingerprint.getService() 去取得我們的 HAL Service 以外,同時做了 mDaemon.setNotify(mDaemonCallback)。這裡的意思是說底層有甚麼事就都跟 mDaemonCallback 說吧!

而當底層 HAL Service 感應到了指紋並註冊成功時就會通知身為 IBiometricsFingerprintClientCallback 的 mDaemonCallback。而當 mDaemonCallback 收到了 onEnrollResult,就呼叫了 handleEnrollResult:

在這裡總算看到 client.onEnrollResult 了,這就是 EnrollClient 的 onEnrollResult 被呼叫的起始點了!

那就讓我們來整理一下整個 Code Flow 吧!

FingerprintService: FingerprintServiceWrapper: enroll

FingerprintService: startEnrollment

EnrollClient: start

IBiometricsFingerprint: enroll

HAL Service

FingerprintService: IBiometricsFingerprintClientCallback: onEnrollResult

FingerprintService: handleEnrollResult

EnrollClient: onEnrollResult

EnrollClient: sendEnrollResult

FingerprintManager: IFingerprintServiceReceiver: onEnrollResult

FingerprintManager: MyHandler: handleMessage

FingerprintManager: MyHandler: sendEnrollResult

FingerprintManager: EnrollmentCallback: onEnrollmentProgress

APP

最後其他 authenticate、remove、enumerate 的流程其實也都大同小異,了解之後再去看應該就會更容易看懂了,希望能夠幫到大家節省一點追蹤的時間囉。

下次我們再來介紹 Fingerprint HAL Service。

--

--