創建 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 接口

子系統的構建配置通過 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.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);
};

添加功能時:

  • 名稱要簡潔。避免將 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用於藍牙相關的配置項。