HAL 介面定義語言 (HIDL) 是用於指定的介面說明語言 (IDL) HAL 和 GCP 之間的介面 對使用者而言。HIDL 可讓您指定類型和方法呼叫,並收集到 介面和套件廣義來說,HIDL 是一種通訊系統 找出可獨立編譯的程式碼集。
HIDL 的用途是供處理序間通訊 (IPC) 使用,以 HDL 建立的 HAL 稱為繫結式 HAL 的概念,因為兩者能透過繫結器與其他架構層通訊 處理序間通訊 (IPC) 呼叫。繫結化 HAL 會在用戶端以外的獨立程序中執行 使用該 API 的應用程式適用對象 必須連結到處理程序的程式庫,直通式 模式也可使用 (Java 不支援)。
HIDL 用於指定資料結構和方法簽章,並以介面分類 (類似於類別) 收集到套件中C++ 的 HIDL 語法看起來很熟悉, Java 程式設計師,但使用一組不同的 。HIDL 也會使用 Java 樣式的註解。
術語
本節使用下列 HIDL 相關字詞:
繫結 | 表示程序之間的遠端程序呼叫使用 HIDL, 也就是透過類似 Binder 的機制實作另請參閱快速導入。 |
---|---|
回呼、非同步回呼 | 由 HAL 使用者提供的介面,並傳遞至 HAL (使用 HIDL 方法);以及 HAL 呼叫以便隨時傳回資料。 |
回呼、同步 | 將伺服器的 HIDL 方法實作所提供的資料傳回至用戶端。 不適用於傳回空白或單一原始值的方法。 |
client | 呼叫特定介面方法的程序。HAL 或 Android 架構 可能是不同介面的用戶端和另一個介面的伺服器。其他參考資訊 直通式。 |
延伸 | 表示可將方法和/或類型新增至其他介面的介面。 一個介面只能擴充另一個介面。適用於未成年人 針對相同套件名稱或新套件 (例如供應商) 遞增的版本 擴充功能),以便在較舊的套件上建構。 |
產生 | 指出可將值傳回用戶端的介面方法。返回 一個非原始值,或多個值、同步回呼函式 。 |
介面 | 方法和類型的集合。在 C++ 或 Java 中轉譯為類別。所有語言 方法皆以相同的方向呼叫:用戶端程序 叫用由伺服器程序實作的方法。 |
單程 | 套用至 HIDL 方法時,表示該方法未傳回任何值,且 它不會封鎖 |
包裹 | 共用版本的介面和資料類型集合。 |
直通 | 伺服器是共用程式庫的 HIDL 模式,dlopen
用戶端會進行後續通訊直通模式是指用戶端和伺服器的流程相同,但
獨立的程式碼集僅適用於將舊版程式碼集帶入 HIDL 模型。
另請參閱繫結機制。 |
伺服器 | 實作介面方法的程序。其他參考資訊 直通式。 |
交通 | 在伺服器和用戶端之間移動資料的 HIDL 基礎架構。 |
version | 套件的版本。由兩個整數組成,即主要和次要。未成年人 版本遞增可能會新增類型和方法,但不會變更。 |
HIDL 設計
HIDL 的目標就是 Android 架構不必費心手動更新
重建 HALHAL 是由廠商或 SOC 製造商建構的
裝置上的 /vendor
分區,獨立啟用 Android 架構
),以 OTA 取代,不重新編譯 HAL。
HIDL 設計可平衡下列顧慮:
- 互通性。建立可靠互通的介面 能以不同架構、工具鍊、 和建構設定HIDL 介面已經過版本管理,無法變更 發布後的畫面
- 效率。HIDL 會試著減少複製的數量 作業。HIDL 定義的資料會以 C++ 標準版面配置的形式傳送至 C++ 程式碼 不必解壓縮即可使用的資料結構。此外,HIDL 也提供 由於 RPC 本身就有點慢,因此 HIDL 支援 在不使用 RPC 呼叫的情況下傳輸資料的方法:共用記憶體和快速 訊息佇列 (FMQ)。
- 符合直覺。HIDL 藉由以下方式,
針對遠端程序呼叫僅使用
in
參數 (請參閱 Android 介面定義語言 (AIDL));無法有效率地達成的值 是透過回呼函式傳回傳回的方法。也沒有傳遞資料 轉移至 HIDL 以執行轉移,或接收來自 HIDL 的資料,變更 資料:擁有權一律會由呼叫函式保持。資料需 僅保留於呼叫函式的持續時間,而且可能會遭到刪除 緊接在呼叫函式傳回後立即顯示
使用直通模式
如要將搭載舊版 Android 的裝置更新至 Android O,您可以採取下列做法: 將傳統 (及舊版) HAL 納入新的 HIDL 介面,為 HAL。這個包裝 HAL 和 Android 架構的公開透明
直通模式僅適用於 C++ 用戶端和實作。 搭載舊版 Android 的裝置不會以 Java 編寫 HAL,因此 Java HAL 本身就具有繫結機制。
直通式標頭檔案
編譯 .hal
檔案時,hidl-gen
會產生
除了標頭以外,還會加上額外的直通標頭檔案 BsFoo.h
用於繫結器通訊;這個標頭會定義要
dlopen
。當直通 HAL 執行相同程序
通常會直接叫用
函式呼叫 (相同執行緒)。oneway
方法會在專屬執行緒中執行
不應等待 HAL 處理 (也就是任何 HAL)
如要在直通模式下使用 oneway
方法,就必須確保執行緒安全。
有了 IFoo.hal
,BsFoo.h
會包裝 HIDL 產生的
提供其他功能 (例如製作 oneway
)
筆交易會在另一個執行緒中執行)。這個檔案類似於
不過,BpFoo.h
而不是使用繫結器呼叫 IPC,
即可直接叫用所需函式HAL 的未來實作
可提供多個實作方法,例如 FooFast HAL 和
食物 HAL。在這種情況下,每個額外實作都有一個檔案
(例如「PTFooFast.cpp
」和
PTFooAccurate.cpp
)。
繫結直通 HAL
您可以繫結至支援直通模式的 HAL 實作。假設
HAL 介面 a.b.c.d@M.N::IFoo
,已建立兩個套件:
a.b.c.d@M.N::IFoo-impl
。包含 HAL 的實作 並公開函式IFoo* HIDL_FETCH_IFoo(const char* name)
啟用 舊版裝置,這個套件存在dlopen
,實作項目為 使用HIDL_FETCH_IFoo
執行個體化。您可以產生基本程式碼 使用hidl-gen
、-Lc++-impl
和-Landroidbp-impl
。a.b.c.d@M.N::IFoo-service
。開啟直通 HAL 和 本身就註冊為繫結化服務,實現相同的 HAL 實作 可做為直通式和繫結式使用
指定的類型為 IFoo
,您可以呼叫 sp<IFoo>
IFoo::getService(string name, bool getStub)
來取得執行個體的存取權
(共 IFoo
個)。如果 getStub
為 true,getService
僅會試圖以直通模式開啟 HAL。如果 getStub
是
否,getService
會嘗試尋找繫結化服務。如果那個
就會嘗試尋找直通服務getStub
參數,除非
defaultPassthroughServiceImplementation
。(裝置推出時,
Android O 是完全繫結的裝置,因此以直通模式開啟服務
。)
HIDL 文法
HIDL 語言在設計上與 C 類似 (但並未使用 C
預先處理器)。除了明確用法外,以下未提及的所有標點符號
=
和 |
) 為文法的一部分。
注意:如要進一步瞭解 HIDL 程式碼樣式,請參閱 程式碼樣式指南 -
/** */
表示說明文件註解。可套用 只有型別、方法、欄位和列舉值宣告。/* */
表示多行註解。//
表示行尾的註解。之外的項目//
,換行符號與其他空白字元相同。- 在下方文法範例中,文字是從
//
到結尾 該行並非文法的一部分,而是在文法上加註。 [empty]
表示字詞可以留空。?
後面有常值或字詞,表示這是選用項目。...
表示包含零或多個項目的序列, 依指示分隔標點符號。HIDL 中沒有變數引數。- 逗號用來分隔序列元素。
- 每個元素都會以半形分號終止,包括最後一個元素。
- UPPERCASE 不成立。
italics
是權杖系列,例如integer
或identifier
(標準 C 剖析規則)。constexpr
是 C 樣式常數運算式 (例如1 + 1
和1L << 3
)。import_name
是套件或介面名稱, 如 HIDL 中所述 版本管理:- 小寫
words
即為常值權杖。
例子:
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr