接口和包

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 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中進行了廣泛討論)。

接口位於與設備無關的位置

在實踐中,建議在分支之間共享接口。這允許在不同設備和用例中最大限度地重複使用代碼和最大限度地測試代碼。