iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 7
0
  • Guide:
    • Treble 是什麼?
    • Treble 架構
    • HIDL 概述
    • HIDL 編碼規範
    • HIDL 中的 hidl-gen 使用
    • HIDL interface 和 package
    • HIDL import & inheritance
    • HIDL 實作

前言

Android HIDL (1) 一文中提到了Android 8.0 之後使用 Treble 的架構,

為了解決 Android 系統的碎片化問題和提高系統更新的效率,

減少了 framework 和 HAL 的耦合性,進而引出了 HIDL 的概念。

本文將詳細的總結 HIDL 的使用。


介紹

HAL接口定義語言或 HIDL(發音為“hide-l”)是一種接口描述語言 (IDL) ,
用於指定 HAL 與其用戶之間的接口。
在 interfaces 和 packages 中它允許指定 types 和 methods 的調用。
更廣泛地說,HIDL 是用於在可以獨立編譯的代碼庫之間進行通信的系統。

HIDL 旨在用於 inter-process communication (IPC),
HIDL 的語法對於 C++ 和 Java 程序員來說看起來比較親和一點,
且這種封裝對於 HAL 和Android 框架來說都是透明的。


類型

簡單講就是利用一個 service 主要呼叫 HAL 層來運作。
假設你宣告了一個 HAL interface 名稱叫做 a.b.c.d@M.N::IFoo
兩個 package 會被產生如下:

  • a.b.c.d@M.N::IFoo-impl
    看到這個不用害怕,有邊讀邊、沒邊讀中間。
    前面那些 abcd 先不用管他,impl 看起來就是 implementation 的縮寫,
    所以直覺上來猜就是實作 HAL。
    至於要怎麼實作呢?
    透過 hidl-gen-Lc++-impl-Landroidbp-impl 工具,
    會產生基本的函式作修改,
    用來給傳統的 dlopen 函式來讀寫。
    以 NFC 為例子大概長這樣:(但 1.0 版已廢棄,使用 1.1 版)
    hardware/interfaces/nfc/1.0/default/Nfc.cpp

      78 INfc* HIDL_FETCH_INfc(const char * /*name*/) {
      79     nfc_nci_device_t* nfc_device;
      80     int ret = 0;
      81     const hw_module_t* hw_module = nullptr;
      82
      83     ret = hw_get_module (NFC_NCI_HARDWARE_MODULE_ID, &hw_module);
      84     if (ret == 0) {
      85         ret = nfc_nci_open (hw_module, &nfc_device);
      86         if (ret != 0) {
      87             ALOGE ("nfc_nci_open failed: %d", ret);
      88         }
      89     }
      90     else
      91         ALOGE ("hw_get_module %s failed: %d", NFC_NCI_HARDWARE_MODULE_ID, ret);
      92
      93     if (ret == 0) {
      94         return new Nfc(nfc_device);
      95     } else {
      96         ALOGE("Passthrough failed to load legacy HAL.");
      97         return nullptr;
      98     }
      99 }
    
  • a.b.c.d@M.N::IFoo-service
    可以是簡單的 passthrough 模式如下:
    hardware/interfaces/nfc/1.0/default/service.cpp

      11 int main() {
      12     return defaultPassthroughServiceImplementation<INfc>();
      13 }
    

    假如要用 Binderized 模式產生一個新的 IPC 來運行的話,
    你可以透過呼叫 sp<IFoo> IFoo::getService(string name, bool getStub)
    來得到 IFoo 的訪問權限。
    如果 getStub 為 True,則 getService 會嘗試僅在 passthrough 模式下打開 HAL。
    如果 getStub 為 False,則 getService 會嘗試找到 Binderized 服務;
    如果未找到,則它會嘗試找到直通式服務。
    除了在 defaultPassthroughServiceImplementation 中,
    其餘情況一律不得使用 getStub 參數。
    (搭載Android O的設備是完全Binder化的設備,因此不得在 passthrough 模式下打開服務。)


語法

  • /** */

    表示文檔註釋。這些只能應用於 type、method、field 和 enum 宣告中。

  • /* */

    表示多行註釋。

  • ////

    表示對行尾的註釋。除此之外,換行符與任何其他空格相同。

  • 在下面的示例語法中,從行**//**到結尾的文本不是語法的一部分,而是對語法的註釋。

  • [empty]

    意味著該術語可能為空。

  • ?

    遵循文字或術語意味著它是可選的。

  • ...

    表示包含零個或多個項目的序列,如圖所示具有分隔標點符號。HIDL中沒有可變參數。

  • 逗號分隔序列元素。

  • 分號終止每個元素,包括最後一個元素。

  • 大寫是一個非終結者。

  • 小寫是文字標記 (token)。

  • italics

    是一個標記 (token) 系列,如 integeridentifier (標準C解析規則)。

  • constexpr

    是一個C風格的常量表達式(例如 1 + 11L << 3)。

  • import_name

    是一個 package 或 interface 名稱,符合 HIDL Versioning 描述。

範例:

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

Reference:

HIDL | Android Open Source Project


上一篇
[Day-06] Android HIDL (1) Treble
下一篇
[Day-08] Android HIDL (3) 編碼規範
系列文
Android Pie 底層開發學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言