資料類型

HIDL 資料宣告會產生 C++ 標準版面配置資料結構。這些 可以放置在感覺自然的地方 (在堆疊、檔案或 全域範圍或堆積上),並且可以使用相同的方式組成。客戶 程式碼呼叫 HIDL Proxy 程式碼傳入常數參照和原始型別。 虛設常式和 Proxy 程式碼則隱藏序列化的詳細資料。

注意:目前沒有任何程式碼是由開發人員編寫的程式碼 對資料結構明確序列化或反序列化所需的項目。

下表將 HIDL 基元對應至 C++ 資料類型:

HIDL 類型 C++ 類型 標題/程式庫
enum enum class
uint8_t..uint64_t uint8_t..uint64_t <stdint.h>
int8_t..int64_t int8_t..int64_t <stdint.h>
float float
double double
vec<T> hidl_vec<T> libhidlbase
T[S1][S2]...[SN] T[S1][S2]...[SN]
string hidl_string libhidlbase
handle hidl_handle libhidlbase
safe_union (custom) struct
struct struct
union union
fmq_sync MQDescriptorSync libhidlbase
fmq_unsync MQDescriptorUnsync libhidlbase

以下各節詳細說明資料類型。

列舉

HIDL 中的列舉成為 C++ 中的列舉。例如:

enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 };
enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };

... 變成:

enum class Mode : uint8_t { WRITE = 1, READ = 2 };
enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };

從 Android 10 開始,列舉可疊代 過度使用 ::android::hardware::hidl_enum_range。這個範圍 包含每個列舉器,依照 HIDL 原始碼中出現的順序,從 從父項列舉到最後一個子項舉例來說,以下程式碼 超過 WRITEREADNONECOMPARE。指定上述 SpecialMode

template <typename T>
using hidl_enum_range = ::android::hardware::hidl_enum_range<T>

for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}

hidl_enum_range 也會實作反向疊代器, 用於 constexpr 情境。如果值出現在列舉中 重複的值,就會重複出現在範圍中。

Bitfield<T>

bitfield<T> (T 是使用者定義的列舉) 成為該列舉在 C++ 中的基礎型別。在上述範例中 bitfield<Mode> 會變成 uint8_t

vec<T>

hidl_vec<T> 類別範本隸屬於 libhidlbase,且可用於傳送任何 HIDL 類型的向量, 任意大小可比較的固定大小容器是 hidl_arrayhidl_vec<T> 也可以 已初始化為指向 T 類型的外部資料緩衝區,會使用 hidl_vec::setToExternal() 函式。

除了在生成的 C++ 標頭,使用 vec<T> 會產生一些便利性 要轉譯為 std::vector 和裸機 T 的函式 指標。如果 vec<T> 做為參數使用,函式 同時傳遞 HIDL 結構和 std::vector<T> 類型 參數。

陣列

Hidl 中的常數陣列以 hidl_array 類別表示 位置:libhidlbasehidl_array<T, S1, S2, …, SN> 代表 N 維固定大小陣列 T[S1][S2]…[SN]

string

hidl_string 類別 (libhidlbase 的一部分) 可以 用於透過 HIDL 介面傳遞字串, /system/libhidl/base/include/hidl/HidlSupport.h。第一個儲存空間 類別中的位置是一個指向其字元緩衝區的指標。

hidl_string 知道如何相互轉換 std::string and char* (C 樣式字串) 使用 operator=、隱式轉換和 .c_str() 函式。 HIDL 字串結構具有適當的複製建構函式和指派方式 運算子:

  • std::string 或 C 字串載入 HIDL 字串。
  • 從 HIDL 字串建立新的 std::string

此外,HIDL 字串也擁有轉換建構函式,因此 C 字串 (char *) 和 C++ 字串 (std::string) 可用於 採用 HIDL 字串的方法。

結構體

HIDL 中的 struct 只能包含固定大小的資料類型, 函式。HIDL 結構定義直接對應至標準版面配置 C++ 中的 struct,確保 struct 具有 一致的記憶體配置結構體可包含 HIDL 類型,包括 handlestringvec<T>, 指向不同的可變長度緩衝區。

帳號

警告:任何種類的地址 (包括實體地址) 裝置位址) 一律不得當做原生控制代碼的一部分。傳送此要求 程序之間的資訊很危險,因此容易遭受攻擊。 程序之間傳遞的所有值都必須經過驗證,才能用於 避免在處理程序中配置記憶體否則,錯誤的帳號代碼可能會造成不良 記憶體存取或記憶體損毀的情況

handle 類型以 hidl_handle 表示 C++ 中的結構,這是一種簡單的包裝函式,指向 const native_handle_t 物件 (在 Android 中已有 這類字詞)。

typedef struct native_handle
{
    int version;        /* sizeof(native_handle_t) */
    int numFds;         /* number of file descriptors at &data[0] */
    int numInts;        /* number of ints at &data[numFds] */
    int data[0];        /* numFds + numInts ints */
} native_handle_t;

根據預設,hidl_handle 不會取得擁有權 其包裝的 native_handle_t 指標內。它只是安全的存在 儲存指向 native_handle_t 的指標,以便用於 包括 32 位元和 64 位元程序

在以下情況下,hidl_handle 擁有其封閉檔案 描述元包括:

  • 呼叫 setTo(native_handle_t* handle, bool shouldOwn) 方法,並將 shouldOwn 參數設為 true
  • 透過複製結構建立 hidl_handle 物件時 來自另一個 hidl_handle 物件
  • 從其他物件複製 hidl_handle 物件時 hidl_handle 個物件

hidl_handle 能同時帶來隱含和明確的轉換 傳入/傳出 native_handle_t* 物件的物件。容器的主要用途 HIDL 中的 handle 類型是透過 HIDL 傳遞檔案描述元 存取 API因此,單一檔案描述元會以 不含 int 和一個的 native_handle_t fd。如果用戶端和伺服器是透過不同的程序運作,RPC 就會是 會自動處理檔案描述元 這兩個程序可在同一個檔案上運作

雖然由hidl_handle 程序有效,而且在接收端中持續有效 函式 (函式傳回時就會關閉)。為此,您要 仍然能持續存取檔案描述元,必須dup() 封閉式檔案描述元,或複製整個 hidl_handle 物件。

記憶事項

HIDL memory 類型對應至 hidl_memory 類別 libhidlbase 中,代表未對應的共用記憶體。這是 此物件必須在程序之間傳遞,才能在 HIDL 中分享記憶體。目的地: 使用共用回憶集錦:

  1. 取得 IAllocator 的例項 (目前僅限執行個體 "ashmem"可用空間) 並用來分配共用記憶體。
  2. IAllocator::allocate() 會傳回 hidl_memory 物件,可透過 HIDL RPC 傳遞,並能使用 libhidlmemorymapMemory 函式。
  3. mapMemory 會傳回對 可用來存取記憶體的 sp<IMemory> 物件。 (IMemoryIAllocator 定義於 android.hidl.memory@1.0)。

IAllocator 的執行個體可用來分配記憶體:

#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::hardware::hidl_memory;
....
  sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
  ashmemAllocator->allocate(2048, [&](bool success, const hidl_memory& mem) {
        if (!success) { /* error */ }
        // now you can use the hidl_memory object 'mem' or pass it around
  }));

記憶體的實際變更必須透過 IMemory 完成 物件,可以是建立於 mem 的側邊 透過 HIDL RPC 接收該資料

// Same includes as above

sp<IMemory> memory = mapMemory(mem);
void* data = memory->getPointer();
memory->update();
// update memory however you wish after calling update and before calling commit
data[0] = 42;
memory->commit();
// …
memory->update(); // the same memory can be updated multiple times
// …
memory->commit();

介面

介面可做為物件傳遞。可以使用「interface」字樣 做為 android.hidl.base@1.0::IBase 類型的語法糖; 此外,目前的介面和所有匯入的介面都已定義 做為一種類型

保留介面的變數應採用強而有力的指標: sp<IName>。採用介面參數的 HIDL 函式 將原始指標轉換為強有指標,導致非直覺的行為 (指標可無預警清除)。為了避免發生問題,請一律儲存 HIDL 做為 sp<> 的介面使用。