Jenis data

Deklarasi data HIDL menghasilkan struktur data tata letak standar C++. Ini struktur dapat ditempatkan di mana saja yang terasa alami (di atas tumpukan, di dalam file atau global, atau pada heap) dan dapat disusun dengan cara yang sama. Klien kode memanggil kode {i>proxy<i} HIDL yang meneruskan referensi konstanta dan tipe primitif, sedangkan stub dan kode {i>proxy<i} menyembunyikan detail serialisasi.

Catatan: Tidak ada kode yang ditulis developer yang 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 ini menjelaskan jenis data secara lebih mendetail.

enum

Enum dalam HIDL menjadi enum dalam C++. 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 diiterasi berlebihan menggunakan ::android::hardware::hidl_enum_range. Rentang ini mencakup setiap enumerator dalam urutan yang muncul dalam kode sumber HIDL, mulai dari enum induk hingga turunan terakhir. Misalnya, kode ini mengiterasi di atas 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 sebuah nilai muncul dalam enumerasi beberapa kali, nilai akan muncul dalam rentang beberapa kali.

bitfield<T>

bitfield<T> (dengan T adalah enum yang ditentukan pengguna) menjadi jenis yang mendasari 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 berupa diinisialisasi untuk mengarah ke buffer data eksternal jenis T, menggunakan fungsi hidl_vec::setToExternal().

Selain memunculkan/menyisipkan struct dengan tepat dalam header C++, penggunaan vec<T> menghasilkan beberapa kemudahan fungsi untuk menerjemahkan ke/dari std::vector dan T tanpa www pointer. Jika vec<T> digunakan sebagai parameter, fungsi tersebut menggunakan kelebihan beban (dua prototipe dibuat) untuk menerima dan teruskan struct HIDL dan jenis std::vector<T> untuk .

array

Array konstanta dalam hidl diwakili oleh class hidl_array dalam libhidlbase. hidl_array<T, S1, S2, …, SN> mewakili array ukuran tetap N dimensi T[S1][S2]…[SN].

string

Class hidl_string (bagian dari libhidlbase) dapat berupa digunakan untuk meneruskan {i>string<i} melalui antarmuka HIDL dan didefinisikan dalam /system/libhidl/base/include/hidl/HidlSupport.h. Penyimpanan pertama lokasi di class merupakan pointer ke buffer karakternya.

hidl_string tahu cara mengonversi ke dan dari std::string and char* (string gaya C) menggunakan operator=, transmisi implisit, dan fungsi .c_str(). Struct string HIDL memiliki konstruktor dan penetapan salinan yang sesuai operator ke:

  • Muat string HIDL dari string std::string atau C.
  • Buat std::string baru dari string HIDL.

Selain itu, {i>string<i} HIDL memiliki konstruktor konversi sehingga {i>string<i} C String (char *) dan C++ (std::string) dapat digunakan di metode yang mengambil string HIDL.

struktur

struct di HIDL hanya dapat berisi jenis data berukuran tetap dan tidak fungsi-fungsi lainnya. Definisi struct HIDL dipetakan langsung ke tata letak standar struct di C++, yang memastikan bahwa struct memiliki dan tata letak memori yang konsisten. Sebuah struct dapat mencakup jenis HIDL, termasuk handle, string, dan vec<T>, yang menunjuk ke buffer panjang variabel yang terpisah.

handle

PERINGATAN: Segala jenis alamat (bahkan alamat fisik alamat perangkat) tidak boleh menjadi bagian dari nama sebutan channel native. Meneruskan ini informasi antar proses berbahaya dan membuat mereka rentan terhadap serangan. Setiap nilai yang diteruskan di antara proses harus divalidasi sebelum digunakan untuk memori yang dialokasikan dalam suatu proses. Jika tidak, penanganan yang buruk dapat menyebabkan masalah akses memori atau kerusakan memori.

Jenis handle direpresentasikan oleh hidl_handle di C++, yang merupakan wrapper sederhana di sekitar pointer ke Objek const native_handle_t (ini telah ada di Android selama 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 dari pointer native_handle_t yang digabungkannya. Program ini hanya ada untuk melindungi menyimpan pointer ke native_handle_t sedemikian rupa sehingga dapat digunakan di proses 32-bit dan 64-bit.

Skenario saat hidl_handle memiliki file yang tertutup deskripsi tersebut meliputi:

  • Mengikuti panggilan ke metode setTo(native_handle_t* handle, bool shouldOwn) dengan parameter shouldOwn yang disetel ke true
  • Saat objek hidl_handle dibuat dengan konstruksi teks dari objek hidl_handle lain
  • Saat objek hidl_handle disalin dan ditetapkan dari objek lain hidl_handle objek

hidl_handle memberikan konversi implisit dan eksplisit dari objek native_handle_t* . Penggunaan utama untuk Jenis handle dalam HIDL adalah meneruskan deskriptor file melalui HIDL antarmuka. Oleh karena itu, satu deskriptor file diwakili oleh native_handle_t tanpa int dan satu fd. Jika klien dan server hidup dalam proses yang berbeda, PPK implementasi secara otomatis menangani deskriptor file untuk kedua proses dapat beroperasi pada file yang sama.

Meskipun deskriptor file diterima dalam hidl_handle oleh valid dalam proses itu, dan tidak berlangsung di luar proses penerimaan (tutup saat fungsi kembali). Sebuah proses yang ingin mempertahankan akses persisten ke deskriptor file harus dup() deskriptor file yang tertutup, 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. Kepada menggunakan memori bersama:

  1. Dapatkan instance IAllocator (saat ini hanya instance "ashmem" tersedia) dan menggunakannya untuk mengalokasikan memori bersama.
  2. IAllocator::allocate() menampilkan 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 aktual pada memori harus dilakukan melalui IMemory 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 sugar sintaksis untuk jenis android.hidl.base@1.0::IBase; sebagai tambahan, antarmuka saat ini dan antarmuka yang diimpor akan ditentukan sebagai suatu jenis.

Variabel yang menyimpan Antarmuka harus berupa pointer yang kuat: sp<IName>. Fungsi HIDL yang mengambil parameter antarmuka mengonversi pointer mentah menjadi pointer yang kuat, menyebabkan perilaku yang tidak intuitif (pointer dapat terhapus secara tidak terduga). Untuk menghindari masalah, selalu simpan HIDL antarmuka sebagai sp<>.