介面與套餐

HIDL 圍繞著介面構建,介面是物件導向語言中用於定義行為的抽象類型。每個接口都是包的一部分。

套餐

套件名稱可以有子級別,例如package.subpackage 。已發布的 HIDL 套件的根目錄是hardware/interfacesvendor/vendorName (例如,對於 Pixel 設備, vendor/google )。包名在根目錄下形成一個或多個子目錄;定義包的所有檔案都位於同一目錄中。例如, package android.hardware.example.extension.light@2.0可以在hardware/interfaces/example/extension/light/2.0下找到。

下表列出了包前綴和位置:

包前綴地點介面類型
android.hardware.* hardware/interfaces/*哈爾
android.frameworks.* frameworks/hardware/interfaces/*框架/相關
android.system.* system/hardware/interfaces/*系統/相關
android.hidl.* system/libhidl/transport/*

套件目錄包含副檔名為.hal的檔案。每個檔案必須包含一個package語句,命名該檔案所屬的套件和版本。文件types.hal (如果存在)不定義接口,而是定義包中每個接口可訪問的資料類型。

介面定義

除了types.hal之外,所有其他.hal檔案都定義了一個介面。介面通常定義如下:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

沒有明確extends聲明的介面隱式擴展自android.hidl.base@1.0::IBase (類似於 Java 中的java.lang.Object )。隱式導入的IBase 介面聲明了幾個不應該也不可能重新聲明的保留方法在使用者定義的介面中或以其他方式使用。這些方法包括:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

輸入

import語句是 HIDL 機制,用於存取另一個套件中的套件介面和類型。 import聲明本身涉及兩個實體:

  • import實體,可以是包,也可以是介面;和
  • import實體,也可以是套件或介面。

進口實體由import聲明的位置決定。當該語句位於包的types.hal內部時,導入的內容對整個包都是可見的;這是包級導入。當語句位於介面檔案內部時,導入實體就是介面本身;這是介面級導入。

導入的實體由import關鍵字後面的值決定。該值不必是完全限定的名稱;如果省略某個元件,則會自動填入目前套件中的資訊。對於完全限定值,支援以下導入情況:

  • 整包進口。如果該值是套件名稱和版本(語法如下所述),則整個套件將匯入到匯入實體中。
  • 部分進口。如果值為:
    • 介面、套件的types.hal和該介面被導入到導入實體中。
    • types.hal中定義的 UDT,則僅將該 UDT 匯入到匯入實體中(不匯入types.hal中的其他類型)。
  • 僅類型導入。如果該值使用上述部分匯入的語法,但使用關鍵字types而不是介面名稱,則僅匯入指定包的types.hal中的 UDT。

進口實體可以存取以下組合:

  • 導入包的公共 UDT 定義在types.hal中;
  • 導入套件的介面(對於整個套件導入)或指定的介面(對於部分導入),用於呼叫它們、向它們傳遞句柄和/或從它們繼承。

import 語句使用完全限定類型名稱語法來提供要匯入的套件或介面的名稱和版本:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

介面繼承

介面可以是先前定義的介面的擴充。擴充可以是以下三種類型之一:

  • 介面可以為另一個介面添加功能,而無需更改其 API。
  • 包可以為另一個包添加功能,而無需更改其 API。
  • 介面可以從套件或特定介面匯入類型。

一個介面只能擴充另一個介面(無多重繼承)。具有非零次版本號的套件中的每個介面都必須擴展該套件的先前版本中的介面。例如,如果derivative套件版本 4.0 中的介面IBar是基於(擴充) original套件版本 1.2 中的介面IFoo ,並且建立了original套件版本 1.3,則IBar版本 4.1 無法擴充IFoo版本 1.3。相反, IBar版本 4.1 必須擴充IBar版本 4.0,該版本與IFoo版本 1.2 相關。如有需要, IBar 5.0 版可以擴充IFoo 1.3 版。

介面擴充並不意味著產生的程式碼中存在庫依賴或跨 HAL 包含 — 它們只是在 HIDL 層級導入資料結構和方法定義。 HAL 中的每個方法都必須在該 HAL 中實現。

供應商擴展

在某些情況下,供應商擴展將作為表示它們擴展的核心介面的基礎物件的子類別來實現。相同的物件將在基本 HAL 名稱和版本以及擴展的(供應商)HAL 名稱和版本下註冊。

版本控制

包是有版本的,接口也有其包的版本。版本以兩個整數表示, major次要的

  • 主要版本不向後相容。增加主版本號碼會將次版本號碼重設為 0。
  • 次要版本向後相容。增加次要版本號表示較新的版本完全向後相容以前的版本。可以新增新的資料結構和方法,但不能更改現有的資料結構或方法簽章。

HAL 的多個主要或次要版本可以同時存在於裝置上。但是,次要版本應該優於主要版本,因為與先前次要版本介面配合使用的客戶端程式碼也將與同一介面的後續次要版本配合使用。有關版本控制和供應商擴展的更多詳細信息,請參閱HIDL 版本控制

介面佈局總結

本節總結如何管理 HIDL 介面套件(例如hardware/interfaces )並整合了整個 HIDL 部分中提供的資訊。在閱讀之前,請確保您熟悉HIDL 版本控制Hashing with hidl-gen中的哈希概念、一般使用 HIDL的詳細資訊以及以下定義:

學期定義
應用程式二進位介面 (ABI)應用程式介面+任何所需的二進位連結。
完全限定名稱 (fqName)用於區分 hidl 類型的名稱。範例: android.hardware.foo@1.0::IFoo
包裹包含 HIDL 介面和類型的套件。範例: android.hardware.foo@1.0
包根目錄包含 HIDL 介面的根包。範例:HIDL 介面android.hardware位於包根目錄android.hardware.foo@1.0
包根路徑Android 原始碼樹中包根會對應到的位置。

如需更多定義,請參閱 HIDL術語

每個檔案都可以從包根映射及其完全限定名稱中找到

包根指定為hidl-gen作為參數-r android.hardware:hardware/interfaces 。例如,如果套件是vendor.awesome.foo@1.0::IFoo並且發送hidl-gen -r vendor.awesome:some/device/independent/path/interfaces ,則介面檔案應位於$ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal

在實務中,建議名為awesome供應商或OEM將其標準介面放在vendor.awesome中。選擇包路徑後,不得更改它,因為它已融入介面的 ABI 中。

包路徑映射應該是唯一的

例如,如果您有-rsome.package:$PATH_A-rsome.package:$PATH_B ,則$PATH_A必須等於$PATH_B才能獲得一致的介面目錄(這也使版本控制介面變得更加容易)。

包根目錄必須有版本控製文件

如果您建立一個套件路徑,例如-r vendor.awesome:vendor/awesome/interfaces ,您還應該建立檔案$ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt ,其中應包含使用-Lhash產生的介面的雜湊值hidl-gen中的選項(這在Hashing with hidl-gen中進行了廣泛討論)。

介面位於與設備無關的位置

在實踐中,建議在分支之間共享介面。這樣可以實現最大程度的程式碼重用以及跨不同裝置和用例的最大程度的程式碼測試。