Jenis data

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 parameter shouldOwn ditetapkan ke true
  • Saat objek hidl_handle dibuat dengan pembuatan salinan dari objek hidl_handle lain
  • Saat objek hidl_handle ditetapkan salinan dari objek hidl_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:

  1. Dapatkan instance IAllocator (saat ini hanya instance "ashmem" yang tersedia) dan gunakan untuk mengalokasikan memori bersama.
  2. IAllocator::allocate() menampilkan objek hidl_memory yang dapat diteruskan melalui HIDL RPC dan dipetakan ke dalam proses menggunakan fungsi mapMemory libhidlmemory.
  3. mapMemory menampilkan referensi ke objek sp<IMemory> yang dapat digunakan untuk mengakses memori. (IMemory dan IAllocator ditentukan di android.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<>.