Android Fingerprint Framework (3): Fingerprint HAL

蔣承達 (Jazz)
9 min readMar 22, 2019

--

HIDL

要介紹 Fingerprint HAL 不免要講到一些 Android HIDL (HAL Interface Definition Langauge) 的內容:

自 Android O 開始 Android 導入了 HIDL 結構,希望進一步切開上層系統與硬體的依賴關係。簡單的來說 HIDL 其實就類似 HAL 版本的 AIDL (Android Interface Definition Langauge),基本上使用起來就像是我們定義了一個介面,讓上層與硬體都基於這個介面來溝通。
這樣即使上層整個刷新成更新的版本,例如說 Android Q,也可以藉由同樣的介面與這支手機的硬體溝通了。更好的是 HIDL 處理進程間通訊的實作細節都已經被包裝起來了,不需要我們煩惱,所以使用起來相當的簡單。

在 HIDL 的架構下,Android 在啟動時會啟動一個獨立進程 (Process) 的 Service 來處理這個 HAL 的工作,而需要使用 HAL 的人就可以透過 HIDL 這個介面請 Service 做事情,因此在本文中我們會分別稱呼這兩個部分為 Fingerprint HAL “Service“ 與 Fingerprint HAL "Interface"。

接下來就讓我們看看他是怎麼實現的吧。

Fingerprint HAL Interface

Fingerprint HAL Interface的介面主要的目錄在
/hardware/interfaces/biometrics/fingerprint/2.1/

Android.bp

先來看看掌管編譯的 Android.bp 吧

簡單的看一下幾個重點:
1. HAL 的模組名稱將會叫做 android.hardware.biometrics.fingerprint@2.1
2. HAL 相關的內容定義在三隻 .hal 檔中
3. 除了一般編譯給 c 語言使用,在這裡宣告也會開啟編譯 java 語言的版本

因為有 gen_java,所以我們在 FingerprintService.java 之中才可以直接 import 來使用:

而這裡 import 的 Class,就是來自 HAL 目錄下的兩隻檔案的內容:

IBiometricsFingerprint.hal
IBiometricsFingerprintClientCallback.hal

IBiometricsFingerprintClientCallback.hal

IBiometricsFingerprintClientCallback 的內容比較簡單:

如上一篇提到的,我們會在 FingerprintService 裡面實作 IBiometricsFingerprintClientCallback 裡的所有 function,再透過 setNotify 來傳給 HAL Service,用來接收 HAL 回傳的訊息。

而每個 function 開頭寫的 oneway 是甚麼意思呢?在官網的說明是:

When applied to a HIDL method, indicates the method returns no values and does not block.

大概就是說這樣的 function 因為沒有 return 值所以也不需要另外一端等待 (Block),射後不理就可以了(!?)

IBiometricsFingerprint.hal

而在 IBiometricsFingerprint 的內容就是定義了 HAL Service 主要支援的 function,像我們所主要關注的 enroll 就是會接受 hat, gid, timeoutSec 這三個參數。
而 function 最後的 generates 就是會 return 甚麼值給呼叫者的意思,這裡的 enroll 就是會回傳一個 RequestStatus,也就是 Error Code 了。

像 RequestStatus 這類型態的定義我們都會寫在 types.hal 之中:

types.hal

顧名思義,整個 HAL 會使用到的類別都會寫在 types.hal 裡面

講到這裡,讓上下層溝通的 HAL Interface 已經介紹完了,那 HAL 怎麼執行任務呢?也就是 HAL Service 的內容,讓我們繼續看下去。

Fingerprint HAL Service

HAL Service 的位置剛好位於 HAL Interface 的下一層目錄:
/hardware/interfaces/biometrics/fingerprint/2.1/default/

Android.bp
android.hardware.biometrics.fingerprint@2.1-service.rc
BiometricsFingerprint.cpp
BiometricsFingerprint.h
service.cpp

Android.bp

一樣我們從 Android.bp 開始看起,詳細內容請看注解:

所以我們會從這些檔案中編譯出一個 Library 叫做 android.hardware.biometrics.fingerprint@2.1-service.so ,然後同時看到了這裡有指定一個 init_rc 的檔案
android.hardware.biometrics.fingerprint@2.1-service.rc,內容是:

最主要的內容是第一行,我們會在開機時將編譯出來的 android.hardware.biometrics.fingerprint@2.1-service.so 啟動成一個叫做 vendor.fps_hal 的 Service,這也是為什麼我們一直說這是一個 HAL Service 的原因。

service.cpp

那這個 HAL Service 啟動時要做些甚麼事呢?
這我們就必須看到 service.cpp 裡頭的 main() 了
hardware/interfaces/biometrics/fingerprint/2.1/default/service.cpp

這裡面提到了一些 ThreadPool 的事情看起來就跟 IPC 機制有關係,我們先不要太在意他弄得太復雜,這裡主要做的事情就是呼叫 BiometricsFingerprint::getInstance() 來產生一個 BiometricsFingerprint 物件,並使用 bio->registerAsService() 叫他去註冊成 Service。

不過 BiometricsFingerprint 為什麼可以呼叫 registerAsService 阿?

BiometricsFingerprint.h

就讓我們看到:
hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h

這裡開宗明義說明了 BiometricsFingerprint 是繼承自 IBiometricsFingerprint,而 registerAsService 就是 IBiometricsFingerprint 的功能。他的實作內容是在編譯 IBiometricsFingerprint.hal 時自動產生的,讓我們可以直接使用。一樣的我們就先不討論太多包裝起來的細節,所以現在 BiometricsFingerprint 已經註冊成 Service 可以讓人呼叫了。

還記得在 FingerprintService 之中我們怎麼使用他嗎?

mDaemon = IBiometricsFingerprint.getService();

這裡 getService 取出的,自然就是呼叫 registerAsService 的 BiometricsFingerprint 本人囉。

到這裡為止 HIDL 做為一個介面的功能已經大致講完了,系統將 hal 檔自動編譯成 Interface 讓上下層分別引入使用,來協助上下層的溝通。並且在開機時啟動並註冊一個 Service,這個 Service 會將 BiometricsFingerprint 實體化並且註冊成可以調用。等 FingerprintService 需要的時候再呼叫 getService 取出,就可以呼叫進 BiometricsFingerprint 裡的 Function 了。

BiometricsFingerprint.cpp

如果還想知道 BiometricsFingerprint 的實作內容就可以看
hardware/interfaces/biometrics/fingerprint/2.1/default/
BiometricsFingerprint.cpp

首先在 service.cpp 裡被調用的 getInstance 是一個 Singleton 的模式,保證同時只會有一個 BiometricsFingerprint 的物件存在,不會重複建立Fingerprint 的實體。

而在建立物件的建構子之中調用了 openHal 來打開 HAL Library。

openHal 之中最重要的就是會透過 hw_get_module 去開啟名字叫做 FINGERPRINT_HARDWARE_MODULE_ID 的 HAL Library,而我們 HAL Service 被呼叫的功能最後就會再呼叫 HAL Library 裡的功能來實現。

就像是我們關注的 enroll 功能,在最後一行呼叫了 mDevice->enroll 來實現功能,這裡的 mDevice 就是 HAL Library。

至於最後的最後,到底名為 FINGERPRINT_HARDWARE_MODULE_ID 的 HAL Library 到底是誰呢?這一般都是提供 Fingerprint 硬體模組的廠商會提供的,廠商會實作他們所需要的邏輯以及與 Driver 溝通的方法,其中的邏輯細節就不需要手機廠商來煩惱囉。

終於藉由這三篇文章我們了解 FingerprintManager、FingerprintService、Fingerprint HAL 之間的關係與連結方法,也可以藉由 Fingerprint 這個簡單的原件可以對其他 Android 中更複雜原件的架構有初步的認識。

希望可以對大家有所幫助!

--

--

蔣承達 (Jazz)

Thundercomm - Software Development Manager