Deklarasi data HIDL menghasilkan struktur data tata letak standar C++. Struktur ini dapat ditempatkan di mana saja yang terasa alami (di tumpukan, di file atau cakupan global, atau di heap) dan dapat disusun dengan cara yang sama. Kode klien memanggil kode proksi HIDL yang meneruskan referensi const dan tipe primitif, sedangkan kode stub dan proksi menyembunyikan detail serialisasi.
Catatan: Kode yang ditulis pengembang tidak diperlukan untuk membuat serialisasi atau deserialisasi struktur data secara eksplisit.
Tabel di bawah memetakan primitif HIDL ke tipe data C++:
Tipe HIDL | Tipe C++ | Tajuk/Perpustakaan |
---|---|---|
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 tipe data secara lebih rinci.
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 diulang menggunakan ::android::hardware::hidl_enum_range
. Rentang ini mencakup setiap enumerator sesuai urutan kemunculannya dalam kode sumber HIDL, mulai dari enum induk hingga turunan terakhir. Misalnya, kode ini mengulangi WRITE
, READ
, NONE
, dan COMPARE
dalam urutan itu. Mengingat 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 suatu nilai muncul dalam enumerasi beberapa kali, nilai tersebut muncul dalam rentang tersebut beberapa kali.
bidang bit<T>
bitfield<T>
(di mana T
adalah enum yang ditentukan pengguna) menjadi tipe dasar enum tersebut di C++. Dalam contoh di atas, bitfield<Mode>
menjadi uint8_t
.
vektor<T>
Templat kelas hidl_vec<T>
adalah bagian dari libhidlbase
dan dapat digunakan untuk meneruskan vektor tipe HIDL apa pun dengan ukuran sewenang-wenang. Kontainer ukuran tetap yang sebanding adalah hidl_array
. hidl_vec<T>
juga dapat diinisialisasi untuk menunjuk ke buffer data eksternal bertipe T
, menggunakan fungsi hidl_vec::setToExternal()
.
Selain memancarkan/memasukkan struct dengan tepat di header C++ yang dihasilkan, penggunaan vec<T>
menghasilkan beberapa fungsi praktis untuk menerjemahkan ke/dari std::vector
dan pointer T
kosong. Jika vec<T>
digunakan sebagai parameter, fungsi yang menggunakannya akan kelebihan beban (dua prototipe akan dihasilkan) untuk menerima dan meneruskan struct HIDL dan tipe std::vector<T>
untuk parameter tersebut.
Himpunan
Array konstan di hidl diwakili oleh kelas hidl_array
di libhidlbase
. hidl_array<T, S1, S2, …, SN>
mewakili array ukuran tetap berdimensi N T[S1][S2]…[SN]
.
rangkaian
Kelas hidl_string
(bagian dari libhidlbase
) dapat digunakan untuk meneruskan string melalui antarmuka HIDL dan didefinisikan dalam /system/libhidl/base/include/hidl/HidlSupport.h
. Lokasi penyimpanan pertama di kelas adalah penunjuk ke buffer karakternya.
hidl_string
mengetahui cara mengonversi ke dan dari std::string and char*
(string gaya C) menggunakan operator=
, cast implisit, dan fungsi .c_str()
. Struct string HIDL memiliki konstruktor salinan dan operator penugasan 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.
struktur
Sebuah struct
di HIDL hanya dapat berisi tipe data berukuran tetap dan tidak ada fungsi. Definisi struct HIDL dipetakan langsung ke struct
s tata letak standar di C++, memastikan bahwa struct
s memiliki tata letak memori yang konsisten. Sebuah struct dapat menyertakan tipe HIDL, termasuk handle
, string
, dan vec<T>
, yang mengarah ke buffer dengan panjang variabel yang terpisah.
menangani
PERINGATAN: Alamat apa pun (bahkan alamat perangkat fisik) tidak boleh menjadi bagian dari nama asli. Melewati informasi ini antar proses berbahaya dan membuatnya rentan terhadap serangan. Nilai apa pun yang diteruskan antar proses harus divalidasi sebelum digunakan untuk mencari alokasi memori dalam suatu proses. Jika tidak, penanganan yang buruk dapat menyebabkan akses memori buruk atau kerusakan memori.
Tipe handle
diwakili oleh struktur hidl_handle
di C++, yang merupakan pembungkus sederhana di sekitar pointer ke objek const native_handle_t
(ini sudah ada di Android sejak lama).
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 alih kepemilikan pointer native_handle_t
yang dibungkusnya. Itu hanya ada untuk menyimpan pointer dengan aman ke native_handle_t
sehingga dapat digunakan dalam proses 32 dan 64-bit.
Skenario di mana hidl_handle
memiliki deskriptor file terlampir meliputi:
- Setelah panggilan ke metode
setTo(native_handle_t* handle, bool shouldOwn)
dengan parametershouldOwn
disetel ketrue
- Ketika objek
hidl_handle
dibuat dengan menyalin konstruksi dari objekhidl_handle
lain - Ketika objek
hidl_handle
disalin dari objekhidl_handle
lainnya
hidl_handle
menyediakan konversi implisit dan eksplisit ke/dari objek native_handle_t*
. Kegunaan utama tipe handle
di HIDL adalah untuk meneruskan deskriptor file melalui antarmuka HIDL. Oleh karena itu, deskriptor file tunggal diwakili oleh native_handle_t
tanpa int
s dan fd
tunggal. Jika klien dan server berada dalam proses yang berbeda, implementasi RPC akan secara otomatis menangani deskriptor file untuk memastikan kedua proses dapat beroperasi pada file yang sama.
Meskipun deskriptor file yang diterima dalam hidl_handle
oleh suatu proses akan valid dalam proses tersebut, deskriptor tersebut tidak akan bertahan di luar fungsi penerima (akan ditutup setelah fungsi kembali). Suatu proses yang ingin mempertahankan akses persisten ke deskriptor file harus dup()
deskriptor file yang disertakan, atau menyalin seluruh objek hidl_handle
.
Penyimpanan
Tipe memory
HIDL dipetakan ke kelas hidl_memory
di libhidlbase
, yang mewakili memori bersama yang belum dipetakan. Ini adalah objek yang harus dilewati antar 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()
mengembalikan objekhidl_memory
yang dapat dilewatkan melalui HIDL RPC dan dipetakan ke dalam proses menggunakan fungsimapMemory
libhidlmemory
. -
mapMemory
mengembalikan referensi ke objeksp<IMemory>
yang dapat digunakan untuk mengakses memori. (IMemory
danIAllocator
didefinisikan diandroid.hidl.memory@1.0
.)
Sebuah instance dari 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
atau 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 gula sintaksis untuk tipe android.hidl.base@1.0::IBase
; selain itu, antarmuka saat ini dan antarmuka apa pun yang diimpor akan ditentukan sebagai sebuah tipe.
Variabel yang menampung Antarmuka harus menjadi petunjuk yang kuat: sp<IName>
. Fungsi HIDL yang mengambil parameter antarmuka akan mengubah pointer mentah menjadi pointer kuat, menyebabkan perilaku non-intuitif (pointer dapat dihapus secara tidak terduga). Untuk menghindari masalah, selalu simpan antarmuka HIDL sebagai sp<>
.