建立 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 適用於藍牙相關設定項目。