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 原始碼中出現的順序,從
從父項列舉到最後一個子項舉例來說,以下程式碼
超過 WRITE
、READ
、NONE
和
COMPARE
。指定上述 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_array
。hidl_vec<T>
也可以
已初始化為指向 T
類型的外部資料緩衝區,會使用
hidl_vec::setToExternal()
函式。
除了在生成的
C++ 標頭,使用 vec<T>
會產生一些便利性
要轉譯為 std::vector
和裸機 T
的函式
指標。如果 vec<T>
做為參數使用,函式
同時傳遞 HIDL 結構和 std::vector<T>
類型
參數。
陣列
Hidl 中的常數陣列以 hidl_array
類別表示
位置:libhidlbase
。hidl_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 類型,包括
handle
、string
和vec<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 中分享記憶體。目的地:
使用共用回憶集錦:
- 取得
IAllocator
的例項 (目前僅限執行個體 "ashmem"可用空間) 並用來分配共用記憶體。 IAllocator::allocate()
會傳回hidl_memory
物件,可透過 HIDL RPC 傳遞,並能使用libhidlmemory
的mapMemory
函式。mapMemory
會傳回對 可用來存取記憶體的sp<IMemory>
物件。 (IMemory
和IAllocator
定義於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<>
的介面使用。