您必須使用 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 版) 中分組。舉例來說,如要為 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
適用於藍牙相關設定項目。