Jenis Data

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 parameter shouldOwn disetel ke true
  • Ketika objek hidl_handle dibuat dengan menyalin konstruksi dari objek hidl_handle lain
  • Ketika objek hidl_handle disalin dari objek hidl_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:

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