Deklarasi data HIDL menghasilkan struktur data tata letak standar C++. Struktur ini dapat ditempatkan di mana saja yang terasa alami (di stack, di file atau cakupan global, atau di heap) dan dapat disusun dengan cara yang sama. Kode klien memanggil kode proxy HIDL yang meneruskan referensi const dan jenis primitif, sedangkan kode stub dan proxy menyembunyikan detail serialisasi.
Catatan: Kode yang ditulis developer tidak pernah diperlukan untuk melakukan serialisasi atau deserialisasi struktur data secara eksplisit.
Tabel di bawah memetakan primitif HIDL ke jenis data C++:
Jenis HIDL | Jenis C++ | Header/library |
---|---|---|
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 |
Bagian di bawah menjelaskan jenis data secara lebih mendetail.
enum
Enum di HIDL menjadi enum di C++. Misalnya:
enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 }; enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };
… menjadi:
enum class Mode : uint8_t { WRITE = 1, READ = 2 }; enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };
Mulai Android 10, enum dapat di-iterasi
menggunakan ::android::hardware::hidl_enum_range
. Rentang ini
menyertakan setiap enumerator dalam urutan yang muncul dalam kode sumber HIDL, mulai
dari enum induk hingga turunan terakhir. Misalnya, kode ini melakukan iterasi
di WRITE
, READ
, NONE
, dan
COMPARE
dalam urutan tersebut. Dengan SpecialMode
di atas:
template <typename T> using hidl_enum_range = ::android::hardware::hidl_enum_range<T> for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}
hidl_enum_range
juga mengimplementasikan iterator terbalik dan dapat
digunakan dalam konteks constexpr
. Jika nilai muncul dalam enumerasi
beberapa kali, nilai tersebut akan muncul dalam rentang beberapa kali.
bitfield<T>
bitfield<T>
(dengan T
adalah enum yang ditentukan pengguna)
menjadi jenis dasar enum tersebut di C++. Dalam contoh di atas,
bitfield<Mode>
menjadi uint8_t
.
vec<T>
Template class hidl_vec<T>
adalah bagian dari
libhidlbase
dan dapat digunakan untuk meneruskan vektor jenis HIDL apa pun dengan
ukuran arbitrer. Penampung ukuran tetap yang sebanding adalah
hidl_array
. hidl_vec<T>
juga dapat
diinisialisasi untuk mengarah ke buffering data eksternal jenis T
, menggunakan
fungsi hidl_vec::setToExternal()
.
Selain memunculkan/menyisipkan struct dengan tepat dalam header
C++ yang dihasilkan, penggunaan vec<T>
menghasilkan beberapa fungsi
kemudahan untuk menerjemahkan ke/dari pointer std::vector
dan T
kosong. Jika vec<T>
digunakan sebagai parameter, fungsi
yang menggunakannya akan kelebihan beban (dua prototipe dihasilkan) untuk menerima dan
meneruskan struct HIDL dan jenis std::vector<T>
untuk parameter
tersebut.
array
Array konstan di hidl diwakili oleh class hidl_array
di libhidlbase
. hidl_array<T, S1, S2, …,
SN>
mewakili array ukuran tetap dimensi N
T[S1][S2]…[SN]
.
string
Class hidl_string
(bagian dari libhidlbase
) dapat
digunakan untuk meneruskan string melalui antarmuka HIDL dan ditentukan di
/system/libhidl/base/include/hidl/HidlSupport.h
. Lokasi penyimpanan pertama
di class adalah pointer ke buffer karakternya.
hidl_string
mengetahui cara mengonversi ke dan dari
std::string and char*
(string bergaya C) menggunakan
operator=
, transmisi implisit, dan fungsi .c_str()
.
Struktur string HIDL memiliki konstruktor salinan dan operator
penetapan yang sesuai untuk:
- Muat string HIDL dari
std::string
atau string C. - Buat
std::string
baru dari string HIDL.
Selain itu, string HIDL memiliki konstruktor konversi sehingga string C
(char *
) dan string C++ (std::string
) dapat digunakan pada
metode yang menggunakan string HIDL.
struct
struct
di HIDL hanya dapat berisi jenis data berukuran tetap dan tidak
memiliki fungsi. Definisi struct HIDL dipetakan langsung ke struct
tata letak standar di C++, memastikan bahwa struct
memiliki
tata letak memori yang konsisten. Struktur dapat menyertakan jenis HIDL, termasuk
handle
, string
, dan vec<T>
, yang
menunjuk ke buffering panjang variabel terpisah.
handle
PERINGATAN: Alamat apa pun (bahkan alamat perangkat fisik) tidak boleh menjadi bagian dari nama sebutan native. Meneruskan informasi ini antarproses berbahaya dan membuatnya rentan terhadap serangan. Setiap nilai yang diteruskan antarproses harus divalidasi sebelum digunakan untuk mencari memori yang dialokasikan dalam proses. Jika tidak, handle yang buruk dapat menyebabkan akses memori yang buruk atau kerusakan memori.
Jenis handle
diwakili oleh struktur
hidl_handle
di C++, yang merupakan wrapper sederhana di sekitar pointer ke
objek const native_handle_t
(ini telah ada di Android selama
bertahun-tahun).
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;
Secara default, hidl_handle
tidak mengambil kepemilikan
kursor native_handle_t
yang digabungkan. Fungsi ini hanya ada untuk
menyimpan pointer ke native_handle_t
dengan aman sehingga dapat digunakan dalam
proses 32-bit dan 64-bit.
Skenario saat hidl_handle
memiliki deskripsi file
terlampirnya meliputi:
- Setelah panggilan ke metode
setTo(native_handle_t* handle, bool shouldOwn)
dengan parametershouldOwn
ditetapkan ketrue
- Saat objek
hidl_handle
dibuat dengan pembuatan salinan dari objekhidl_handle
lain - Saat objek
hidl_handle
ditetapkan salinan dari objekhidl_handle
lain
hidl_handle
menyediakan konversi implisit dan eksplisit
ke/dari objek native_handle_t*
. Penggunaan utama untuk
jenis handle
di HIDL adalah untuk meneruskan deskripsi file melalui antarmuka
HIDL. Oleh karena itu, satu deskripsi file diwakili oleh
native_handle_t
tanpa int
dan satu
fd
. Jika klien dan server berada dalam proses yang berbeda, implementasi RPC
akan otomatis menangani deskripsi file untuk memastikan
kedua proses dapat beroperasi pada file yang sama.
Meskipun deskripsi file yang diterima di hidl_handle
oleh
proses valid dalam proses tersebut, deskripsi file tidak akan tetap ada setelah fungsi
penerimaan (deskripsi file ditutup saat fungsi ditampilkan). Proses yang ingin
mempertahankan akses persisten ke deskripsi file harus dup()
deskripsi file yang disertakan, atau menyalin seluruh objek hidl_handle
.
memori
Jenis memory
HIDL dipetakan ke class hidl_memory
di libhidlbase
, yang mewakili memori bersama yang tidak dipetakan. Ini adalah
objek yang harus diteruskan di antara proses untuk berbagi memori di HIDL. Untuk
menggunakan memori bersama:
- Dapatkan instance
IAllocator
(saat ini hanya instance "ashmem" yang tersedia) dan gunakan untuk mengalokasikan memori bersama. IAllocator::allocate()
menampilkan objekhidl_memory
yang dapat diteruskan melalui HIDL RPC dan dipetakan ke dalam proses menggunakan fungsimapMemory
libhidlmemory
.mapMemory
menampilkan referensi ke objeksp<IMemory>
yang dapat digunakan untuk mengakses memori. (IMemory
danIAllocator
ditentukan diandroid.hidl.memory@1.0
.)
Instance IAllocator
dapat digunakan untuk mengalokasikan memori:
#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 }));
Perubahan sebenarnya pada memori harus dilakukan melalui objek
IMemory
, baik di sisi yang membuat mem
maupun di sisi yang
menerimanya melalui 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();
antarmuka
Antarmuka dapat diteruskan sebagai objek. Kata antarmuka dapat digunakan
sebagai sintaksis yang mudah untuk jenis android.hidl.base@1.0::IBase
;
selain itu, antarmuka saat ini dan antarmuka yang diimpor ditentukan
sebagai jenis.
Variabel yang menyimpan Antarmuka harus berupa pointer yang kuat:
sp<IName>
. Fungsi HIDL yang menggunakan parameter antarmuka
mengonversi pointer mentah menjadi pointer kuat, yang menyebabkan perilaku tidak intuitif
(pointer dapat dihapus secara tidak terduga). Untuk menghindari masalah, selalu simpan antarmuka
HIDL sebagai sp<>
.