您必須使用 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用於藍牙相關的配置項。