Tipe Data

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 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 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:

  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 libhidlmemory mapMemory .
  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 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<> .