創建 HAL 接口

您必須使用 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 接口

對於一個構建子系統CONFIGS通過一個HAL接口訪問,而用於給出配置值的接口在HAL包被分組android.hardware.configstore (目前為1.0版本)。例如,為了創建一個HAL接口文件surfaceflinger ,在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.bpAndroid.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);
};

添加函數時:

  • 名字要簡潔。避免轉換生成文件變量名到函數名和牢記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 接口來處理一組相關的配置項。例如, ISurfaceflingerConfigssurfaceflinger -相關的配置項,並IBluetoothConfigs藍牙相關的配置項。