Nội dung khai báo dữ liệu HIDL sẽ tạo cấu trúc dữ liệu bố cục chuẩn C++. Các cấu trúc có thể được đặt ở bất kỳ nơi nào tự nhiên (trên ngăn xếp, trong tệp hoặc toàn cục hoặc trên vùng nhớ khối xếp) và có thể được soạn theo cùng một cách. Khách hàng gọi mã proxy HIDL truyền vào tham chiếu cố định và loại nguyên gốc, còn đoạn mã giả lập và mã proxy sẽ ẩn thông tin chi tiết về quá trình chuyển đổi tuần tự.
Lưu ý: Không có mã nào do nhà phát triển viết cần phải chuyển đổi tuần tự hoặc giải tuần tự cấu trúc dữ liệu một cách rõ ràng.
Bảng dưới đây ánh xạ các dữ liệu nguyên gốc HIDL với các kiểu dữ liệu C++:
Loại HiDL | Loại C++ | Tiêu đề/thư viện |
---|---|---|
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 |
Các phần dưới đây sẽ mô tả chi tiết hơn về các loại dữ liệu.
enum
Một giá trị enum trong HIDL sẽ trở thành một giá trị enum trong C++. Ví dụ:
enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 }; enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };
... trở thành:
enum class Mode : uint8_t { WRITE = 1, READ = 2 }; enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };
Kể từ Android 10, một enum có thể được lặp lại
sử dụng ::android::hardware::hidl_enum_range
. Phạm vi này
bao gồm mọi giá trị enum theo thứ tự xuất hiện trong mã nguồn HIDL, bắt đầu
từ enum mẹ cho đến con cuối cùng. Ví dụ: mã này lặp lại
hơn WRITE
, READ
, NONE
và
COMPARE
theo thứ tự đó. Cho trước SpecialMode
:
template <typename T> using hidl_enum_range = ::android::hardware::hidl_enum_range<T> for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}
hidl_enum_range
cũng triển khai các biến lặp ngược và có thể
được dùng trong constexpr
ngữ cảnh. Nếu một giá trị xuất hiện trong bảng liệt kê
nhiều lần, giá trị sẽ xuất hiện trong dải ô nhiều lần.
trường bit<T>
bitfield<T>
(trong đó T
là một enum do người dùng xác định)
sẽ trở thành loại cơ bản của enum đó trong C++. Trong ví dụ trên,
bitfield<Mode>
trở thành uint8_t
.
vec<T>
Mẫu lớp hidl_vec<T>
là một phần của
libhidlbase
và có thể dùng để truyền một vectơ thuộc loại HIDL bất kỳ có
kích thước tuỳ ý. Vùng chứa kích thước cố định tương đương là
hidl_array
. hidl_vec<T>
cũng có thể là
được khởi tạo để trỏ tới vùng đệm dữ liệu bên ngoài thuộc loại T
, sử dụng
hàm hidl_vec::setToExternal()
.
Ngoài việc phát/chèn cấu trúc một cách thích hợp trong hàm được tạo
trong tiêu đề C++, việc sử dụng vec<T>
sẽ tạo ra sự thuận tiện
các hàm dịch sang/từ std::vector
và T
đơn thuần
con trỏ. Nếu vec<T>
được dùng làm tham số, hàm này
sử dụng nó quá tải (hai nguyên mẫu được tạo) để chấp nhận và
truyền cả cấu trúc HIDL và loại std::vector<T>
cho điều đó
.
mảng
Các mảng không đổi trong hidl được biểu thị bằng lớp hidl_array
trong libhidlbase
. hidl_array<T, S1, S2, …,
SN>
đại diện cho mảng kích thước cố định N kích thước
T[S1][S2]…[SN]
string
Lớp hidl_string
(một phần của libhidlbase
) có thể là
dùng để truyền chuỗi qua giao diện HIDL và được xác định trong
/system/libhidl/base/include/hidl/HidlSupport.h
. Bộ nhớ đầu tiên
vị trí trong lớp là một con trỏ tới vùng đệm ký tự của lớp đó.
hidl_string
biết cách chuyển đổi sang và từ
std::string and char*
(chuỗi kiểu C) sử dụng
operator=
, hệ thống truyền ngầm và hàm .c_str()
.
Cấu trúc chuỗi HIDL có hàm khởi tạo sao chép và chỉ định thích hợp
toán tử để:
- Tải chuỗi HIDL từ một chuỗi
std::string
hoặc C. - Tạo một
std::string
mới từ chuỗi HIDL.
Ngoài ra, chuỗi HIDL có hàm khởi tạo chuyển đổi nên chuỗi C
Chuỗi (char *
) và C++ (std::string
) có thể được sử dụng trên
các phương thức lấy chuỗi HIDL.
cấu trúc
struct
trong HIDL chỉ có thể chứa các kiểu dữ liệu có kích thước cố định và không có
. Định nghĩa cấu trúc HIDL ánh xạ trực tiếp đến bố cục tiêu chuẩn
struct
trong C++, đảm bảo rằng struct
có một
bố cục bộ nhớ nhất quán. Một cấu trúc có thể chứa các loại HIDL, bao gồm
handle
, string
và vec<T>
, điều đó
trỏ đến các vùng đệm có độ dài biến riêng biệt.
tên người dùng
CẢNH BÁO: Địa chỉ dưới bất kỳ loại nào (kể cả địa chỉ thực tế địa chỉ thiết bị) không được nằm trong tên người dùng gốc. Đạt tiêu chuẩn này thông tin giữa các quy trình đều nguy hiểm và dễ bị tấn công. Bất kỳ giá trị nào được truyền giữa các quá trình đều phải được xác thực trước khi được dùng để xem bộ nhớ được phân bổ trong một tiến trình. Nếu không, tên người dùng không hợp lệ có thể gây ra truy cập bộ nhớ hoặc hỏng bộ nhớ.
Loại handle
được biểu thị bằng hidl_handle
cấu trúc trong C++, là một trình bao bọc đơn giản xung quanh con trỏ đến
Đối tượng const native_handle_t
(đối tượng này đã có trong Android cho
trong một khoảng thời gian dài).
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;
Theo mặc định, hidl_handle
không có quyền sở hữu
của con trỏ native_handle_t
mà nó gói. Nó chỉ tồn tại để đảm bảo an toàn
lưu trữ một con trỏ đến native_handle_t
để có thể sử dụng con trỏ đó
cả tiến trình 32 và 64 bit.
Các trường hợp trong đó hidl_handle
sở hữu tệp đi kèm
mô tả bao gồm:
- Theo lệnh gọi đến phương thức
setTo(native_handle_t* handle, bool shouldOwn)
có tham sốshouldOwn
được đặt thànhtrue
- Khi đối tượng
hidl_handle
được tạo bằng cách tạo bản sao từ một đối tượnghidl_handle
khác - Khi đối tượng
hidl_handle
được sao chép từ một đối tượng kháchidl_handle
đối tượng
hidl_handle
cung cấp cả lượt chuyển đổi ngầm ẩn và tường minh
đến/từ đối tượng native_handle_t*
. Mục đích sử dụng chính của
Loại handle
trong HIDL là để truyền chỉ số mô tả tệp qua HIDL
giao diện. Do đó, một chỉ số mô tả tệp được biểu thị bằng một
native_handle_t
không có int
và một
fd
. Nếu máy khách và máy chủ sống trong một tiến trình khác, RPC
sẽ tự động xử lý chỉ số mô tả tệp để đảm bảo
cả hai quy trình đều có thể hoạt động trên cùng một tệp.
Mặc dù chỉ số mô tả tệp nhận được trong hidl_handle
bởi
quá trình hợp lệ trong quá trình đó, nó không tồn tại ngoài phạm vi quá trình nhận
(hàm sẽ đóng khi hàm trả về). Một quy trình muốn
duy trì quyền truy cập liên tục vào chỉ số mô tả tệp phải dup()
chỉ số mô tả tệp đính kèm hoặc sao chép toàn bộ đối tượng hidl_handle
.
bộ nhớ
Loại HIDL memory
liên kết với lớp hidl_memory
trong libhidlbase
, đại diện cho bộ nhớ dùng chung chưa được liên kết. Đây là
đối tượng phải được truyền giữa các quy trình để chia sẻ bộ nhớ trong HIDL. Người nhận
sử dụng bộ nhớ dùng chung:
- Nhận một thực thể của
IAllocator
(hiện chỉ có một thực thể) "ashmem" sẵn) và sử dụng nó để phân bổ bộ nhớ dùng chung. IAllocator::allocate()
trả về mộthidl_memory
đối tượng có thể được truyền qua HIDL RPC và được ánh xạ vào một quy trình sử dụng HàmmapMemory
củalibhidlmemory
.mapMemory
trả về một tham chiếu đến một Đối tượngsp<IMemory>
có thể dùng để truy cập vào bộ nhớ. (IMemory
vàIAllocator
được định nghĩa trongandroid.hidl.memory@1.0
.)
Bạn có thể dùng một thực thể của IAllocator
để phân bổ bộ nhớ:
#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 }));
Các thay đổi thực tế đối với bộ nhớ phải được thực hiện thông qua IMemory
ở phía tạo mem
hoặc ở cạnh mà
nhận được qua 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();
giao diện
Giao diện có thể được truyền dưới dạng đối tượng. Bạn có thể sử dụng từ giao diện
dưới dạng cú pháp dễ hiểu cho kiểu android.hidl.base@1.0::IBase
;
ngoài ra, giao diện hiện tại và bất kỳ giao diện đã nhập nào đều được xác định
làm loại.
Các biến chứa Giao diện phải là con trỏ mạnh:
sp<IName>
. Hàm HIDL nhận tham số giao diện
chuyển đổi con trỏ thô thành con trỏ mạnh, gây ra hành vi không trực quan
(con trỏ có thể bị xoá đột ngột). Để tránh sự cố, hãy luôn lưu trữ HIDL
giao diện dưới dạng sp<>
.