Bagian ini menjelaskan jenis data HIDL. Untuk detail penerapan, lihat HIDL C++ (untuk C++ implementasi) atau HIDL Java (untuk implementasi Java).
Persamaan dengan C++ meliputi:
structs
menggunakan sintaksis C++;unions
mendukung sintaksis C++ secara {i>default<i}. Keduanya harus diberi nama; struktur dan serikat pekerja anonim tidak didukung.- Typedef diizinkan di HIDL (seperti di C++).
- Komentar bergaya C++ diizinkan dan disalin ke file header yang dihasilkan.
Persamaan dengan Java meliputi:
- Untuk setiap file, HIDL mendefinisikan namespace gaya Java yang harus diawali dengan
android.hardware.
. Namespace C++ yang dihasilkan adalah::android::hardware::…
. - Semua definisi file dimuat dalam gaya Java
Wrapper
interface
. - Deklarasi array HIDL mengikuti gaya Java, bukan gaya C++. Contoh:
struct Point { int32_t x; int32_t y; }; Point[3] triangle; // sized array
- Komentar mirip dengan format javadoc.
Representasi data
struct
atau union
yang terdiri dari
Tata Letak Standar
(subset dari persyaratan jenis data lama biasa) memiliki memori yang konsisten
dalam kode C++ yang dihasilkan, diterapkan dengan atribut perataan eksplisit pada
struct
dan union
anggota.
Jenis HIDL primitif, serta enum
dan bitfield
(yang selalu berasal dari tipe primitif), memetakan ke tipe C++ standar
seperti std::uint32_t
dari
cstdint.
Karena Java tidak mendukung jenis yang tidak ditandatangani, jenis HIDL yang tidak ditandatangani dipetakan ke tipe Java bertanda tangan yang sesuai. Struct dipetakan ke class Java; arrays dipetakan ke array Java; unions saat ini tidak didukung pada Java. String disimpan secara internal sebagai UTF8. Karena Java mendukung hanya string UTF16, nilai string yang dikirim ke atau dari implementasi Java diterjemahkan, dan mungkin tidak sama persis pada diterjemahkan ulang karena himpunan karakternya tidak selalu memetakan dengan lancar.
Data yang diterima melalui IPC di C++ ditandai const
dan berada dalam
{i>read-only memory<i} yang bertahan hanya
selama durasi panggilan fungsi. Data
yang diterima melalui IPC di Java telah disalin ke dalam objek Java, sehingga ia dapat
dipertahankan tanpa penyalinan tambahan (dan dapat diubah).
Anotasi
Anotasi bergaya Java dapat ditambahkan ke deklarasi jenis. Anotasi adalah diurai oleh backend Vendor Test Suite (VTS) dari compiler HIDL tetapi tidak ada anotasi yang diuraikan tersebut sebenarnya dipahami oleh kompilator HIDL. Sebagai gantinya, anotasi VTS yang diuraikan ditangani oleh VTS Compiler (VTSC).
Anotasi menggunakan sintaksis Java: @annotation
atau
@annotation(value)
atau @annotation(id=value, id=value…)
dengan nilai dapat berupa ekspresi konstanta, string, atau daftar nilai
di dalam {}
, seperti di Java. Beberapa anotasi dengan nama yang sama
dapat dilampirkan ke item yang sama.
Meneruskan pernyataan
Dalam HIDL, struct mungkin tidak akan dideklarasikan ke depan, sehingga membuat jenis data yang merujuk pada diri sendiri tidak mungkin dilakukan (misalnya, Anda tidak dapat menjelaskan daftar tertaut atau pohon dalam HIDL). Sebagian besar HAL yang sudah ada (sebelum Android 8.x) memiliki penggunaan terbatas deklarasi penerusan, yang dapat dihapus dengan mengatur ulang struktur data deklarasi.
Batasan ini memungkinkan struktur data disalin berdasarkan nilai dengan
{i>deep-copy<i}, alih-alih melacak nilai-nilai {i>pointer<i} yang mungkin terjadi
waktu dalam struktur
data yang merujuk pada dirinya sendiri. Jika data yang sama diteruskan dua kali,
seperti dengan dua parameter metode atau vec<T>
yang mengarah ke
data yang sama, dua salinan terpisah
dibuat dan dikirim.
Deklarasi bertingkat
HIDL mendukung deklarasi bertingkat ke sebanyak mungkin level yang diinginkan (dengan satu pengecualian yang disebutkan di bawah). Contoh:
interface IFoo { uint32_t[3][4][5][6] multidimArray; vec<vec<vec<int8_t>>> multidimVector; vec<bool[4]> arrayVec; struct foo { struct bar { uint32_t val; }; bar b; } struct baz { foo f; foo.bar fb; // HIDL uses dots to access nested type names } …
Pengecualiannya adalah bahwa jenis antarmuka
hanya dapat disematkan dalam
vec<T>
dan hanya dalam satu tingkat (tidak
vec<vec<IFoo>>
).
Sintaksis pointer mentah
Bahasa HIDL tidak menggunakan * dan tidak mendukung fleksibilitas penuh dari pointer mentah C/C++. Untuk mengetahui detail tentang cara HIDL mengenkapsulasi pointer dan array/vektor, lihat vec<T> template.
Antarmuka
Kata kunci interface
memiliki dua penggunaan.
- Perintah ini membuka definisi antarmuka dalam file .hal.
- Ini dapat digunakan sebagai jenis khusus di
bidang struct/union, parameter metode,
dan pengembalian. Ini dipandang sebagai antarmuka
dan sinonim umum untuk
android.hidl.base@1.0::IBase
.
Misalnya, IServiceManager
memiliki metode berikut:
get(string fqName, string name) generates (interface service);
Metode ini berjanji untuk mencari beberapa antarmuka berdasarkan nama. Ini juga
identik untuk mengganti antarmuka dengan android.hidl.base@1.0::IBase
.
Antarmuka hanya dapat diteruskan dengan dua cara: sebagai parameter tingkat atas, atau sebagai
anggota vec<IMyInterface>
. Mereka tidak boleh anggota
vec, struct, array, atau union bertingkat.
MQDescriptorSync dan MQDescriptorUnsync
Jenis MQDescriptorSync
dan MQDescriptorUnsync
meneruskan deskriptor Fast Message Queue (FMQ) yang disinkronkan atau tidak disinkronkan
di seluruh antarmuka HIDL. Untuk mengetahui detailnya, lihat
HIDL C++ (FMQ bukan
didukung di Java).
jenis memori
Jenis memory
digunakan untuk merepresentasikan memori bersama yang tidak dipetakan di
HIDL. Hanya didukung pada C++. Nilai jenis ini dapat digunakan pada
pihak penerima untuk menginisialisasi objek IMemory
, memetakan memori
dan membuatnya dapat digunakan. Untuk mengetahui detailnya, lihat
HIDL C++.
Peringatan: Data terstruktur yang ditempatkan di folder bersama
memori HARUS berupa jenis yang formatnya
tidak pernah berubah sepanjang masa
versi antarmuka yang meneruskan memory
. Jika tidak, HAL dapat mengalami
masalah kompatibilitas yang fatal.
jenis pointer
Jenis pointer
hanya untuk penggunaan internal HIDL.
bitfield<T> jenis template
bitfield<T>
dengan T
adalah
enum yang ditentukan pengguna menunjukkan bahwa nilainya adalah bitwise-OR dari
nilai enum yang ditentukan dalam T
. Dalam kode yang dihasilkan,
bitfield<T>
muncul sebagai jenis T yang mendasarinya. Contoh:
enum Flag : uint8_t { HAS_FOO = 1 << 0, HAS_BAR = 1 << 1, HAS_BAZ = 1 << 2 }; typedef bitfield<Flag> Flags; setFlags(Flags flags) generates (bool success);
Compiler menangani jenis Flag yang sama seperti uint8_t
.
Mengapa tidak digunakan
(u)int8_t
/(u)int16_t
/(u)int32_t
/(u)int64_t
?
Menggunakan bitfield
memberikan informasi HAL tambahan kepada pembaca,
yang sekarang mengetahui bahwa setFlags
mengambil nilai bitwise-OR dari Flag (yaitu
tahu bahwa memanggil setFlags
dengan 16 tidak valid). Tanpa
bitfield
, informasi ini hanya disampaikan melalui dokumentasi. Di beberapa
selain itu, VTS sebenarnya dapat memeriksa apakah nilai
flag adalah bitwise-OR dari Flag.
Tuas jenis primitif
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 mencari memori yang dialokasikan dalam suatu proses. Jika tidak, penanganan yang buruk dapat menyebabkan masalah akses memori atau kerusakan memori.
Semantik HIDL adalah salin-menurut-nilai, yang menyiratkan bahwa parameter disalin.
Setiap potongan data yang besar, atau data yang perlu dibagikan antar-proses
(seperti fence sinkronisasi), ditangani dengan meneruskan deskriptor file yang menunjuk
ke objek persisten: ashmem
untuk memori bersama, file sebenarnya, atau
apa pun yang dapat bersembunyi di balik deskriptor file. Driver binder
menduplikasi deskriptor file ke proses lain.
native_handle_t
Android mendukung native_handle_t
, konsep handle umum
ditentukan di libcutils
.
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;
Pengendali native adalah kumpulan int dan deskriptor file yang diteruskan
berdasarkan nilai. Satu deskriptor file dapat disimpan dalam handle native dengan
tanpa int dan satu deskriptor file. Meneruskan handle menggunakan tuas native
yang dienkapsulasi dengan jenis primitif handle
memastikan bahwa elemen
nama sebutan channel secara langsung
termasuk dalam HIDL.
Karena memiliki ukuran yang bervariasi, native_handle_t
tidak dapat disertakan
secara langsung dalam struct. Bidang {i>handle<i} menghasilkan pointer ke
native_handle_t
yang dialokasikan.
Di versi Android sebelumnya, nama sebutan channel native dibuat menggunakan
fungsi yang ada di
libcutils.
Di Android 8.0 dan yang lebih baru, fungsi ini kini disalin ke
android::hardware::hidl
atau dipindahkan ke NDK. HIDL
kode yang dihasilkan secara otomatis akan
melakukan serialisasi dan {i>deserialisasi<i} fungsi ini secara otomatis,
tanpa keterlibatan dari
kode yang ditulis pengguna.
Menangani dan kepemilikan deskriptor file
Bila Anda memanggil metode antarmuka HIDL yang meneruskan (atau mengembalikan)
Objek hidl_handle
(baik tingkat atas maupun bagian dari jenis gabungan),
kepemilikan deskriptor file yang terkandung di dalamnya adalah sebagai berikut:
- pemanggil meneruskan objek
hidl_handle
sebagai mempertahankan kepemilikan deskriptor file yang terdapat dalamnative_handle_t
wrap wrap; pemanggil harus menutup file ini deskriptor saat hal itu dilakukan dengannya. - Proses yang menampilkan
hidl_handle
(dengan meneruskannya ke fungsi_cb
) mempertahankan kepemilikan deskriptor file yang terdapat dalamnative_handle_t
yang digabungkan oleh objek; proses harus menutup deskriptor file ini jika sudah selesai. - Transpor yang menerima
hidl_handle
memiliki kepemilikan deskriptor file di dalamnative_handle_t
digabungkan oleh objek; penerima dapat menggunakan deskriptor file ini apa adanya selama callback transaksi, namun harus meng-clone handle native untuk menggunakan file di luar callback. Transportasi otomatis memanggilclose()
untuk deskriptor file saat transaksi selesai.
HIDL tidak mendukung handle di Java (karena Java tidak mendukung handle di Java semua).
Array berukuran
Untuk array berukuran dalam HIDL, elemennya dapat berupa struct apa pun dapat berisi:
struct foo { uint32_t[3] x; // array is contained in foo };
String
String terlihat berbeda di C++ dan Java, tetapi transpor yang mendasarinya adalah struktur C++. Untuk mengetahui detailnya, lihat Jenis Data HiDL C++ atau Jenis Data Java HIDL.
Catatan: Meneruskan string ke atau dari Java melalui Antarmuka HIDL (termasuk Java ke Java) menyebabkan konversi himpunan karakter yang mungkin tidak mempertahankan encoding asli.
vec<T> jenis template
Template vec<T>
mewakili buffer berukuran variabel
yang berisi instance T
.
T
dapat berupa salah satu dari hal berikut:
- Jenis primitif (misalnya, uint32_t)
- String
- Enum yang ditentukan pengguna
- Struktur yang ditentukan pengguna
- Antarmuka, atau kata kunci
interface
(vec<IFoo>
,vec<interface>
didukung hanya sebagai parameter tingkat teratas) - Nama sebutan channel
- bitfield<U>
- vec<U>, di mana U ada dalam daftar ini kecuali antarmuka (mis.
vec<vec<IFoo>>
tidak didukung) - U[] (array berukuran U), di mana U ada dalam daftar ini kecuali antarmuka
Jenis yang ditentukan pengguna
Bagian ini menjelaskan jenis yang ditentukan pengguna.
{i>Enumer<i}
HIDL tidak mendukung enum anonim. Jika tidak, enum di HIDL serupa ke C++11:
enum name : type { enumerator , enumerator = constexpr , … }
Enum dasar didefinisikan dalam kaitannya dengan salah satu jenis bilangan bulat di HIDL. Jika tidak nilai ditentukan untuk enumerator pertama enum berdasarkan bilangan bulat , nilai defaultnya adalah 0. Jika tidak ada nilai yang ditentukan untuk enumerator berikutnya, nilai {i>default<i} ke nilai sebelumnya ditambah satu. Contoh:
// RED == 0 // BLUE == 4 (GREEN + 1) enum Color : uint32_t { RED, GREEN = 3, BLUE }
Enum juga dapat mewarisi dari enum yang ditentukan sebelumnya. Jika tidak ada nilai yang
yang ditentukan untuk enumerator pertama enum turunan (dalam hal ini
FullSpectrumColor
), nilainya didefaultkan ke nilai terakhir
enumerator dari enumerasi induk ditambah satu. Contoh:
// ULTRAVIOLET == 5 (Color:BLUE + 1) enum FullSpectrumColor : Color { ULTRAVIOLET }
Peringatan: Pewarisan enum bekerja secara mundur dari sebagian besar jenis pewarisan lainnya. Nilai enum turunan tidak dapat digunakan sebagai nilai enum induk. Hal ini karena enum turunan menyertakan lebih banyak nilai daripada orang tua. Namun, nilai enum induk dapat dengan aman digunakan sebagai nilai enum turunan karena nilai enum turunan menurut definisi adalah superset dari nilai enum induk. Ingatlah hal ini saat mendesain antarmuka karena ini berarti jenis-jenis yang mengacu pada enum induk tidak dapat merujuk ke enum turunan di iterasi berikutnya dari dalam antarmuka berbasis web yang sederhana.
Nilai enum disebut dengan sintaks titik dua (bukan sintaks titik sebagai
jenis bertingkat). Sintaksisnya adalah Type:VALUE_NAME
. Tidak perlu menentukan
jika nilainya direferensikan dalam jenis enum atau jenis turunan yang sama. Contoh:
enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 }; enum Color : Grayscale { RED = WHITE + 1 }; enum Unrelated : uint32_t { FOO = Color:RED + 1 };
Mulai Android 10, enum memiliki
Atribut len
yang dapat digunakan dalam ekspresi konstan.
MyEnum::len
adalah jumlah total entri dalam enumerasi tersebut.
Ini berbeda dari jumlah total nilai, yang mungkin lebih kecil ketika
nilai diduplikasi.
Struktur
HIDL tidak mendukung struct anonim. Jika tidak, struct dalam HIDL sangat mirip dengan C.
HIDL tidak mendukung struktur data panjang-variabel yang terkandung sepenuhnya di dalam
sebuah struct. Termasuk himpunan (array) tak terbatas
yang terkadang digunakan sebagai
isian terakhir dari {i>struct<i} pada
C/C++ (kadang-kadang terlihat
[0]
). vec<T>
HIDL merepresentasikan ukuran dinamis
array dengan data yang disimpan dalam buffer terpisah; instance tersebut diwakili
dengan instance vec<T>
di struct
.
Demikian pula, string
dapat dimuat dalam struct
(buffer terkait terpisah). Dalam C++ yang dihasilkan, instance HIDL
jenis handle ditunjukkan melalui pointer ke handle native yang sebenarnya sebagai
instance dari jenis data pokok memiliki panjang variabel.
Union
HIDL tidak mendukung serikat anonim. Jika tidak, union akan mirip dengan C.
Gabungan tidak boleh berisi jenis perbaikan (seperti pointer, deskriptor file, binder
). Tabel ini tidak memerlukan {i>field<i} khusus atau jenis terkait,
cukup disalin menggunakan memcpy()
atau yang setara. Sebuah serikat pekerja
mungkin tidak secara langsung
berisi (atau berisi menggunakan struktur data lain) apa pun yang memerlukan pengaturan
offset binder (yaitu, referensi antarmuka binder atau handle). Contoh:
union UnionType { uint32_t a; // vec<uint32_t> r; // Error: can't contain a vec<T> uint8_t b;1 }; fun8(UnionType info); // Legal
Gabungan juga dapat dideklarasikan di dalam struct. Contoh:
struct MyStruct { union MyUnion { uint32_t a; uint8_t b; }; // declares type but not member union MyUnion2 { uint32_t a; uint8_t b; } data; // declares type but not member }