HIDL 是圍繞接口構建的,接口是面向對象語言中用於定義行為的抽像類型。每個接口都是包的一部分。
套餐
包名稱可以有子級別,例如package.subpackage
。已發布 HIDL 包的根目錄是hardware/interfaces
或vendor/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 ed實體,它也可以是包或接口。
導入實體由import
語句的位置確定。當語句在包的types.hal
中時,整個包都可以看到正在導入的內容;這是包級別的導入。當語句在接口文件中時,導入實體就是接口本身;這是一個接口級的導入。
導入的實體由import
關鍵字後面的值決定。該值不必是完全限定名稱;如果一個組件被省略,它會自動填充當前包中的信息。對於完全限定值,支持以下導入案例:
- 整包進口。如果值是包名稱和版本(語法如下所述),則整個包被導入到導入實體中。
- 部分進口。如果值為:
- 一個接口、包的
types.hal
和該接口被導入到導入實體中。 - 在
types.hal
中定義的 UDT,然後僅將該 UDT 導入到導入實體中(不導入types.hal
中的其他類型)。
- 一個接口、包的
- 僅類型導入。如果該值使用上述部分導入的語法,但使用關鍵字
types
而不是接口名稱,則僅導入指定包的types.hal
中的 UDT。
進口實體可以訪問以下組合:
- 在
types.hal
中定義的導入包的通用 UDT; - 導入包的接口(用於整個包導入)或指定接口(用於部分導入),用於調用它們、將句柄傳遞給它們和/或從它們繼承。
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 版必須擴展與IFoo
1.2 版綁定的IBar
4.0 版。如果需要, 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中進行了廣泛討論)。
接口位於與設備無關的位置
在實踐中,建議在分支之間共享接口。這允許在不同設備和用例中最大限度地重複使用代碼和最大限度地測試代碼。