您必須使用 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 介面來處理一組相關的設定項。例如surfaceflinger
相關的配置項目為ISurfaceflingerConfigs
,藍牙相關的配置項目為IBluetoothConfigs
。