您必須使用 HIDL,說明用於有條件編譯架構的所有建構標記。相關的建構標記必須分組,並納入單一 .hal 檔案。使用 HIDL 指定設定項目具有下列優點:
- 版本化 (如要新增設定項目,供應商/原始設備製造商必須明確擴充 HAL)
- 說明文件齊全
- 使用 SELinux 控管存取權
- 透過供應商測試套件對設定項目進行健全性檢查 (範圍檢查、項目間的相互依賴檢查等)
- C++ 和 Java 中自動產生的 API
找出架構使用的建構旗標
首先,請找出用於有條件編譯架構的建構設定,然後捨棄過時的設定,縮小設定集。舉例來說,系統會為 surfaceflinger 識別下列建構旗標集:
TARGET_USES_HWC2TARGET_BOARD_PLATFORMTARGET_DISABLE_TRIPLE_BUFFERINGTARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYSNUM_FRAMEBUFFER_SURFACE_BUFFERSTARGET_RUNNING_WITHOUT_SYNC_FRAMEWORKVSYNC_EVENT_PHASE_OFFSET_NSSF_VSYNC_EVENT_PHASE_OFFSET_NSPRESENT_TIME_OFFSET_FROM_VSYNC_NSMAX_VIRTUAL_DISPLAY_DIMENSION
建立 HAL 介面
子系統的建構設定是透過 HAL 介面存取,而提供設定值的介面則會分組在 HAL 套件 android.hardware.configstore 中 (目前為 1.0 版)。舉例來說,如要為 surfaceflinger 建立 HAL 介面檔案,請在 hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal 中執行下列操作:
package android.hardware.configstore@1.0;
interface ISurfaceFlingerConfigs {
// TO-BE-FILLED-BELOW
};
建立 .hal 檔案後,請執行 hardware/interfaces/update-makefiles.sh,將新的 .hal 檔案新增至 Android.bp 和 Android.mk 檔案。
新增建構標記的函式
為每個建構標記在介面中新增函式。例如,在
hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal:
interface ISurfaceFlingerConfigs {
disableTripleBuffering() generates(OptionalBool ret);
forceHwcForVirtualDisplays() generates(OptionalBool ret);
enum NumBuffers: uint8_t {
USE_DEFAULT = 0,
TWO = 2,
THREE = 3,
};
numFramebufferSurfaceBuffers() generates(NumBuffers ret);
runWithoutSyncFramework() generates(OptionalBool ret);
vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret);
presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret);
maxVirtualDisplayDimension() generates(OptionalInt32 ret);
};
新增函式時:
- 名稱簡明扼要。避免將 makefile 變數名稱轉換為函式名稱,並請注意,不再需要
TARGET_和BOARD_前置字串。 - 新增註解。協助開發人員瞭解設定項目的用途、如何變更架構行為、有效值和其他相關資訊。
函式傳回類型可以是 Optional[Bool|String|Int32|UInt32|Int64|UInt64]。型別定義於相同目錄的 types.hal 中,並以欄位包裝原始值,指出值是否由 HAL 指定;如果不是,則會使用預設值。
struct OptionalString {
bool specified;
string value;
};
視情況定義最能代表設定項目類型的列舉,並將該列舉做為傳回型別。在上述範例中,NumBuffers 列舉會定義有效值的數量上限。定義這類自訂資料類型時,請新增欄位或列舉值 (例如 USE_DEFAULT),表示 HAL 是否指定值。
在 HIDL 中,單一建構標記不一定會成為單一函式。模組擁有者也可以將密切相關的建構標記彙整到結構體中,並讓函式傳回該結構體 (這樣做可以減少函式呼叫次數)。
舉例來說,將兩個建構標記匯總至 hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal 中的單一結構體的選項如下:
interface ISurfaceFlingerConfigs {
// other functions here
struct SyncConfigs {
OptionalInt64 vsyncEventPhaseoffsetNs;
OptionalInt64 presentTimeoffsetFromSyncNs;
};
getSyncConfigs() generates (SyncConfigs ret);
// other functions here
};
單一 HAL 函式的替代方案
除了為所有建構標記使用單一 HAL 函式,HAL 介面也提供 getBoolean(string
key) 和 getInteger(string key) 等簡單函式。實際的 key=value 配對會儲存在個別檔案中,HAL 服務會讀取/剖析這些檔案,藉此提供值。
雖然這種方法很容易定義,但不會納入 HIDL 提供的優點 (強制執行版本控管、方便編寫文件、存取控管),因此不建議使用。
單一和多個介面
設定項目的 HAL 介面設計有兩種選擇:
- 單一介面涵蓋所有設定項目
- 多個介面,每個介面涵蓋一組相關設定項目
單一介面較為簡單,但如果單一檔案中新增的設定項目越多,就越難維護。此外,存取控管機制不夠精細,因此獲准存取介面的程序可以讀取所有設定項目 (無法授予部分設定項目的存取權)。如果未授予存取權,就無法讀取設定項目。
由於這些問題,Android 會針對一組相關設定項目,使用多個介面搭配單一 HAL 介面。舉例來說,ISurfaceflingerConfigs 代表與 surfaceflinger 相關的設定項目,IBluetoothConfigs 則代表與藍牙相關的設定項目。