Deklarasi data HIDL menghasilkan struktur data tata letak standar C++. Struktur ini dapat ditempatkan di mana saja yang terasa alami (pada stack, pada file atau lingkup global, atau pada heap) dan dapat disusun dengan cara yang sama. Kode klien memanggil kode proxy HIDL yang meneruskan referensi const dan tipe primitif, sedangkan kode rintisan dan proxy menyembunyikan detail serialisasi.
Catatan: Kode yang ditulis pengembang tidak diperlukan untuk membuat serial atau deserialize struktur data secara eksplisit.
Tabel di bawah ini 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 ini menjelaskan tipe data secara lebih rinci.
enum
Enum di HIDL menjadi enum di C++. Sebagai contoh:
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 dalam urutan yang muncul dalam kode sumber HIDL, mulai dari enum induk hingga anak terakhir. Misalnya, kode ini mengulangi WRITE
, READ
, NONE
, dan COMPARE
dalam urutan itu. Diberikan 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 muncul dalam rentang beberapa kali.
bidang bit<T>
bitfield<T>
(di mana T
adalah enum yang ditentukan pengguna) menjadi tipe yang mendasari enum itu di C++. Dalam contoh di atas, bitfield<Mode>
menjadi uint8_t
.
vec<T>
Templat kelas hidl_vec<T>
adalah bagian dari libhidlbase
dan dapat digunakan untuk melewatkan vektor jenis HIDL apa pun dengan ukuran arbitrer. Wadah ukuran tetap yang sebanding adalah hidl_array
. Sebuah hidl_vec<T>
juga dapat diinisialisasi untuk menunjuk ke buffer data eksternal tipe T
, menggunakan fungsi hidl_vec::setToExternal()
.
Selain memancarkan/menyisipkan 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 baik struct HIDL dan tipe std::vector<T>
untuk parameter tersebut.
Himpunan
Array konstan di hidl diwakili oleh kelas hidl_array
di libhidlbase
. Sebuah hidl_array<T, S1, S2, …, SN>
mewakili sebuah 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 pointer ke buffer karakternya.
hidl_string
mengetahui cara mengonversi ke dan dari std::string and char*
(string gaya-C) menggunakan operator=
, pemeran implisit, dan fungsi .c_str()
. Struktur string HIDL memiliki copy constructor 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
dalam HIDL hanya dapat berisi tipe data ukuran tetap dan tidak ada fungsi. Definisi struct HIDL memetakan langsung ke struct
tata letak standar di C++, memastikan bahwa struct
memiliki tata letak memori yang konsisten. Sebuah struct dapat menyertakan tipe HIDL, termasuk handle
, string
, dan vec<T>
, yang menunjuk ke buffer panjang variabel yang terpisah.
menangani
PERINGATAN: Alamat apa pun (bahkan alamat perangkat fisik) tidak boleh menjadi bagian dari pegangan asli. Melewati informasi ini antar proses berbahaya dan membuat mereka rentan terhadap serangan. Setiap nilai yang dilewatkan di antara proses harus divalidasi sebelum digunakan untuk mencari memori yang dialokasikan dalam suatu proses. Jika tidak, pegangan yang buruk dapat menyebabkan akses memori yang buruk atau kerusakan memori.
Jenis handle
diwakili oleh struktur hidl_handle
di C++, yang merupakan pembungkus sederhana di sekitar pointer ke objek const native_handle_t
(ini telah ada di Android untuk waktu yang 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 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:
- Mengikuti panggilan ke
setTo(native_handle_t* handle, bool shouldOwn)
metode dengan parametershouldOwn
disetel ketrue
- Ketika objek
hidl_handle
dibuat dengan menyalin konstruksi dari objekhidl_handle
lain - Ketika objek
hidl_handle
disalin dari objekhidl_handle
lain
hidl_handle
menyediakan konversi implisit dan eksplisit ke/dari objek native_handle_t*
. Penggunaan utama untuk tipe handle
dalam HIDL adalah untuk meneruskan deskriptor file melalui antarmuka HIDL. Oleh karena itu, deskriptor file tunggal diwakili oleh native_handle_t
tanpa int
s dan satu fd
. Jika klien dan server hidup 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 di hidl_handle
oleh suatu proses akan valid dalam proses itu, itu tidak akan bertahan di luar fungsi penerima (itu akan ditutup setelah fungsi kembali). Proses yang ingin mempertahankan akses tetap ke deskriptor file harus dup()
deskriptor file terlampir, atau menyalin seluruh objek hidl_handle
.
Penyimpanan
Jenis memory
HIDL memetakan ke kelas hidl_memory
di libhidlbase
, yang mewakili memori bersama yang tidak dipetakan. Ini adalah objek yang harus dilewati antara proses untuk berbagi memori dalam 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 fungsilibhidlmemory
mapMemory
. -
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 aktual 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 dilewatkan sebagai objek. Antarmuka kata dapat digunakan sebagai gula sintaksis untuk tipe android.hidl.base@1.0::IBase
; selain itu, antarmuka saat ini dan antarmuka yang diimpor akan didefinisikan sebagai tipe.
Variabel yang menyimpan Antarmuka harus berupa penunjuk 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<>
.