Bagian ini menjelaskan jenis data HIDL. Untuk mengetahui detail penerapan, lihat HIDL C++ (untuk implementasi C++) atau HIDL Java (untuk implementasi Java).
Kesamaan dengan C++ meliputi:
structs
menggunakan sintaksis C++;unions
mendukung sintaksis C++ secara default. Keduanya harus diberi nama; struct dan union anonim tidak didukung.- Typedef diizinkan di HIDL (seperti di C++).
- Komentar bergaya C++ diizinkan dan disalin ke file header yang dihasilkan.
Kesamaan dengan Java meliputi:
- Untuk setiap file, HIDL menentukan namespace bergaya Java yang harus dimulai dengan
android.hardware.
. Namespace C++ yang dihasilkan adalah::android::hardware::…
. - Semua definisi file terdapat dalam wrapper
interface
bergaya Java. - 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
Standard-Layout
(subkumpulan persyaratan jenis data biasa) memiliki tata letak memori
yang konsisten dalam kode C++ yang dihasilkan, yang diterapkan dengan atribut perataan eksplisit pada
anggota struct
dan union
.
Jenis HIDL primitif, serta jenis enum
dan bitfield
(yang selalu berasal dari jenis primitif), dipetakan ke jenis C++ standar
seperti std::uint32_t
dari
cstdint.
Karena Java tidak mendukung jenis yang tidak ditandatangani, jenis HIDL yang tidak ditandatangani dipetakan ke jenis Java bertanda tangan yang sesuai. Struct dipetakan ke class Java; array dipetakan ke array Java; union saat ini tidak didukung di Java. String disimpan secara internal sebagai UTF8. Karena Java hanya mendukung string UTF16, nilai string yang dikirim ke atau dari implementasi Java diterjemahkan, dan mungkin tidak identik saat diterjemahkan ulang karena kumpulan karakter tidak selalu dipetakan dengan lancar.
Data yang diterima melalui IPC di C++ ditandai const
dan berada di
memori hanya baca yang hanya ada selama durasi panggilan fungsi. Data
yang diterima melalui IPC di Java telah disalin ke dalam objek Java, sehingga dapat
dipertahankan tanpa penyalinan tambahan (dan dapat diubah).
Anotasi
Anotasi bergaya Java dapat ditambahkan ke deklarasi jenis. Anotasi diurai oleh backend Vendor Test Suite (VTS) dari compiler HIDL, tetapi tidak ada anotasi yang diuraikan tersebut yang benar-benar dipahami oleh compiler 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 yang mungkin berupa ekspresi konstan, string, atau daftar nilai
di dalam {}
, seperti di Java. Beberapa anotasi dengan nama yang sama
dapat dilampirkan ke item yang sama.
Meneruskan deklarasi
Di HIDL, struct mungkin tidak dideklarasikan ke depan, sehingga jenis data yang ditentukan pengguna dan merujuk pada dirinya sendiri tidak mungkin (misalnya, Anda tidak dapat mendeskripsikan linked list atau hierarki di HIDL). Sebagian besar HAL yang ada (sebelum Android 8.x) memiliki penggunaan deklarasi forward yang terbatas, yang dapat dihapus dengan mengatur ulang deklarasi struktur data.
Batasan ini memungkinkan struktur data disalin menurut nilai dengan deep-copy
sederhana, bukan melacak nilai pointer yang mungkin terjadi beberapa
kali 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 akan dibuat dan dikirim.
Deklarasi bertingkat
HIDL mendukung deklarasi bertingkat ke sebanyak level yang diinginkan (dengan satu pengecualian yang tercantum 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 } …
Pengecualian adalah jenis antarmuka hanya dapat disematkan dalam
vec<T>
dan hanya satu tingkat (tidak ada
vec<vec<IFoo>>
).
Sintaksis pointer mentah
Bahasa HIDL tidak menggunakan * dan tidak mendukung fleksibilitas penuh pointer mentah C/C++. Untuk mengetahui detail tentang cara HIDL mengenkapsulasi pointer dan array/vektor, lihat template vec<T>.
Antarmuka
Kata kunci interface
memiliki dua penggunaan.
- Tindakan ini akan membuka definisi antarmuka dalam file .hal.
- Jenis ini dapat digunakan sebagai jenis khusus di kolom struct/union, parameter metode,
dan hasil. Fungsi ini dipandang sebagai antarmuka umum dan sinonim dengan
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. Hal ini juga
identik dengan 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>
. Elemen ini tidak boleh menjadi anggota
vektor, struct, array, atau union bertingkat.
MQDescriptorSync dan MQDescriptorUnsync
Jenis MQDescriptorSync
dan MQDescriptorUnsync
meneruskan deskripsi Fast Message Queue (FMQ) yang disinkronkan atau tidak disinkronkan
melalui antarmuka HIDL. Untuk mengetahui detailnya, lihat
HIDL C++ (FMQ tidak
didukung di Java).
jenis memori
Jenis memory
digunakan untuk mewakili memori bersama yang tidak dipetakan di
HIDL. Jenis ini hanya didukung di C++. Nilai jenis ini dapat digunakan di
ujung penerima untuk menginisialisasi objek IMemory
, memetakan memori,
dan membuatnya dapat digunakan. Untuk mengetahui detailnya, lihat
HIDL C++.
Peringatan: Data terstruktur yang ditempatkan dalam memori
bersama HARUS berupa jenis yang formatnya tidak pernah berubah selama masa aktif
versi antarmuka yang meneruskan memory
. Jika tidak, HAL dapat mengalami
masalah kompatibilitas fatal.
jenis pointer
Jenis pointer
hanya untuk penggunaan internal HIDL.
Template jenis bitfield<T>
bitfield<T>
dengan T
adalah
enum yang ditentukan pengguna menunjukkan bahwa nilainya adalah bitwise-OR dari
nilai enum yang ditentukan di T
. Dalam kode yang dihasilkan,
bitfield<T>
muncul sebagai jenis dasar T. 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 Flag jenis yang sama dengan uint8_t
.
Mengapa tidak menggunakan
(u)int8_t
/(u)int16_t
/(u)int32_t
/(u)int64_t
?
Menggunakan bitfield
memberikan informasi HAL tambahan kepada pembaca,
yang kini mengetahui bahwa setFlags
mengambil nilai Flag bitwise-OR (yaitu
mengetahui bahwa memanggil setFlags
dengan 16 tidak valid). Tanpa
bitfield
, informasi ini hanya disampaikan melalui dokumentasi. Selain itu, VTS sebenarnya dapat memeriksa apakah nilai flag adalah bitwise-OR dari Flag.
Nama sebutan jenis primitif
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.
Semantik HIDL adalah salin-menurut-nilai, yang menyiratkan bahwa parameter disalin.
Setiap bagian data yang besar, atau data yang perlu dibagikan di antara proses
(seperti pagar sinkronisasi), ditangani dengan meneruskan deskripsi file yang mengarah
ke objek persisten: ashmem
untuk memori bersama, file sebenarnya, atau
hal lain yang dapat disembunyikan di balik deskripsi file. Driver binder
menduplikasi deskriptor file ke dalam proses lain.
native_handle_t
Android mendukung native_handle_t
, konsep nama sebutan umum
yang 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;
Handle native adalah kumpulan int dan deskripsi file yang diteruskan
berdasarkan nilai. Satu deskripsi file dapat disimpan dalam handle native tanpa
int dan satu deskripsi file. Meneruskan handle menggunakan handle native
yang dienkapsulasi dengan jenis primitif handle
memastikan bahwa handle
native disertakan langsung dalam HIDL.
Karena native_handle_t
memiliki ukuran variabel, native_handle_t
tidak dapat disertakan
secara langsung dalam struct. Kolom handle menghasilkan pointer ke native_handle_t
yang dialokasikan secara terpisah.
Pada versi Android sebelumnya, handle native dibuat menggunakan fungsi
yang sama yang ada di
libcutils.
Di Android 8.0 dan yang lebih tinggi, fungsi ini kini disalin ke
namespace android::hardware::hidl
atau dipindahkan ke NDK. Kode yang dihasilkan secara otomatis
oleh HIDL akan melakukan serialisasi dan deserialisasi fungsi ini secara otomatis,
tanpa melibatkan kode yang ditulis pengguna.
Kepemilikan deskriptor file dan nama sebutan file
Saat Anda memanggil metode antarmuka HIDL yang meneruskan (atau menampilkan)
objek hidl_handle
(tingkat atas atau bagian dari jenis gabungan),
kepemilikan deskripsi file yang ada di dalamnya adalah sebagai berikut:
- Pemanggil yang meneruskan objek
hidl_handle
sebagai argumen mempertahankan kepemilikan deskriptor file yang terdapat dalamnative_handle_t
yang digabungkan; pemanggil harus menutup deskriptor file ini setelah selesai menggunakannya. - Proses yang menampilkan objek
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 saat selesai menggunakannya. - Transpor yang menerima
hidl_handle
memiliki kepemilikan deskripsi file di dalamnative_handle_t
yang digabungkan oleh objek; penerima dapat menggunakan deskripsi file ini apa adanya selama callback transaksi, tetapi harus meng-clone handle native untuk menggunakan deskripsi file di luar callback. Transpor akan otomatis memanggilclose()
untuk deskripsi file saat transaksi selesai.
HIDL tidak mendukung handle di Java (karena Java tidak mendukung handle sama sekali).
Array berukuran
Untuk array berukuran dalam struct HIDL, elemennya dapat berupa jenis apa pun yang dapat berisi struct:
struct foo { uint32_t[3] x; // array is contained in foo };
String
String muncul secara berbeda di C++ dan Java, tetapi jenis penyimpanan transpor yang mendasarinya adalah struktur C++. Untuk mengetahui detailnya, lihat Jenis Data HIDL C++ atau Jenis Data HIDL Java.
Catatan: Meneruskan string ke atau dari Java melalui antarmuka HIDL (termasuk Java ke Java) menyebabkan konversi kumpulan karakter yang mungkin tidak mempertahankan encoding asli.
Template jenis vec<T>
Template vec<T>
mewakili buffering 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>
hanya didukung sebagai parameter tingkat atas) - Nama sebutan channel
- bitfield<U>
- vec<U>, dengan U ada dalam daftar ini kecuali antarmuka (misalnya,
vec<vec<IFoo>>
tidak didukung) - U[] (array berukuran U), dengan U ada dalam daftar ini kecuali antarmuka
Jenis yang ditentukan pengguna
Bagian ini menjelaskan jenis yang ditentukan pengguna.
Enum
HIDL tidak mendukung enum anonim. Jika tidak, enum di HIDL mirip dengan C++11:
enum name : type { enumerator , enumerator = constexpr , … }
Enum dasar ditentukan dalam hal salah satu jenis bilangan bulat di HIDL. Jika tidak ada nilai yang ditentukan untuk enumerator pertama enum berdasarkan jenis bilangan bulat, nilai defaultnya adalah 0. Jika tidak ada nilai yang ditentukan untuk penghitung berikutnya, nilai defaultnya adalah 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 ditentukan untuk enumerator pertama enum turunan (dalam hal ini
FullSpectrumColor
), nilai defaultnya adalah nilai enumerator
terakhir dari enum induk ditambah satu. Contoh:
// ULTRAVIOLET == 5 (Color:BLUE + 1) enum FullSpectrumColor : Color { ULTRAVIOLET }
Peringatan: Pewarisan enum berfungsi 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 induk. Namun, nilai enum induk dapat digunakan dengan aman sebagai nilai enum turunan karena nilai enum turunan menurut definisinya adalah superset dari nilai enum induk. Perhatikan hal ini saat mendesain antarmuka karena hal ini berarti jenis yang merujuk ke enum induk tidak dapat merujuk ke enum turunan dalam iterasi antarmuka Anda berikutnya.
Nilai enum dirujuk dengan sintaksis titik dua (bukan sintaksis titik sebagai
jenis bertingkat). Sintaksisnya adalah Type:VALUE_NAME
. Tidak perlu menentukan
jenis jika nilai 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.
Hal ini berbeda dengan jumlah total nilai, yang mungkin lebih kecil jika
nilai diduplikasi.
Struct
HIDL tidak mendukung struct anonim. Jika tidak, struct di HIDL sangat mirip dengan C.
HIDL tidak mendukung struktur data panjang variabel yang sepenuhnya terdapat dalam
struct. Hal ini mencakup array dengan panjang tidak terbatas yang terkadang digunakan sebagai
kolom terakhir struct di C/C++ (terkadang terlihat dengan ukuran
[0]
). HIDL vec<T>
mewakili array dengan ukuran
dinamis dengan data yang disimpan dalam buffer terpisah; instance tersebut direpresentasikan
dengan instance vec<T>
di struct
.
Demikian pula, string
dapat dimuat dalam struct
(buffer terkait terpisah). Dalam C++ yang dihasilkan, instance jenis handle
HIDL direpresentasikan melalui pointer ke handle native yang sebenarnya karena
instance jenis data pokok memiliki panjang variabel.
Union
HIDL tidak mendukung union anonim. Jika tidak, union mirip dengan C.
Union tidak boleh berisi jenis perbaikan (seperti pointer, deskriptor file, objek
binder). Jenis ini tidak memerlukan kolom khusus atau jenis terkait dan
hanya disalin menggunakan memcpy()
atau yang setara. Union mungkin tidak langsung
berisi (atau berisi menggunakan struktur data lain) apa pun yang memerlukan penetapan
offset binder (yaitu, handle atau referensi antarmuka binder). 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
Union 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 }