您必須使用 HIDL 來描述用於有條件地編譯框架的所有構建標誌。相關的構建標誌必須分組並包含在單個.hal
文件中。使用 HIDL 指定配置項包括以下好處:
- 版本化(要添加新的配置項,供應商/OEM 必須明確擴展 HAL)
- 有據可查
- 使用 SELinux 進行訪問控制
- 通過供應商測試套件對配置項進行完整性檢查(範圍檢查、項目之間的相互依賴關係檢查等)
- C++ 和 Java 中自動生成的 API
識別框架使用的構建標誌
首先確定用於有條件地編譯框架的構建配置,然後放棄過時的配置以使集合更小。例如,為surfaceflinger
標識了以下一組構建標誌:
-
TARGET_USES_HWC2
-
TARGET_BOARD_PLATFORM
-
TARGET_DISABLE_TRIPLE_BUFFERING
-
TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
-
NUM_FRAMEBUFFER_SURFACE_BUFFERS
-
TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK
-
VSYNC_EVENT_PHASE_OFFSET_NS
-
SF_VSYNC_EVENT_PHASE_OFFSET_NS
-
PRESENT_TIME_OFFSET_FROM_VSYNC_NS
-
MAX_VIRTUAL_DISPLAY_DIMENSION
創建 HAL 接口
子系統的構建配置通過 HAL 接口訪問,而用於提供配置值的接口被分組在 HAL 包android.hardware.configstore
(當前版本為 1.0)中。例如,要在hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
中為surfaceflinger
創建 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
用於藍牙相關的配置項。