Bahasa definisi antarmuka HAL atau HIDL adalah bahasa deskripsi antarmuka (IDL) untuk menentukan antarmuka antara HAL dan penggunanya. HIDL memungkinkan penentuan jenis dan panggilan metode, yang dikumpulkan ke dalam antarmuka dan paket. Secara lebih luas, HIDL adalah sistem untuk berkomunikasi antar-codebase yang dapat dikompilasi secara independen.
HIDL dimaksudkan untuk digunakan untuk komunikasi antarproses (IPC). HAL yang dibuat dengan HDL disebut HAL binder karena dapat berkomunikasi dengan lapisan arsitektur lain menggunakan panggilan komunikasi antar-proses (IPC) binder. HAL yang di-binderkan berjalan dalam proses terpisah dari klien yang menggunakannya. Untuk library yang harus ditautkan ke proses, mode passthrough juga tersedia (tidak didukung di Java).
HIDL menentukan struktur data dan tanda tangan metode, yang diatur dalam antarmuka (mirip dengan class) yang dikumpulkan ke dalam paket. Sintaksis HIDL terlihat familier bagi programmer C++ dan Java, tetapi dengan kumpulan kata kunci yang berbeda. HIDL juga menggunakan anotasi gaya Java.
Terminologi
Bagian ini menggunakan istilah terkait HIDL berikut:
binderized | Menunjukkan bahwa HIDL sedang digunakan untuk panggilan prosedur jarak jauh di antara proses, yang diimplementasikan melalui mekanisme seperti Binder. Lihat juga passthrough. |
---|---|
callback, asinkron | Antarmuka yang ditayangkan oleh pengguna HAL, diteruskan ke HAL (menggunakan metode HIDL), dan dipanggil oleh HAL untuk menampilkan data kapan saja. |
callback, sinkron | Menampilkan data dari implementasi metode HIDL server ke klien. Tidak digunakan untuk metode yang menampilkan void atau satu nilai primitif. |
klien | Proses yang memanggil metode antarmuka tertentu. Proses framework Android atau HAL dapat berupa klien dari satu antarmuka dan server dari antarmuka lainnya. Lihat juga passthrough. |
memperluas | Menunjukkan antarmuka yang menambahkan metode dan/atau jenis ke antarmuka lain. Antarmuka hanya dapat memperluas satu antarmuka lainnya. Dapat digunakan untuk penambahan versi minor dalam nama paket yang sama atau untuk paket baru (misalnya, ekstensi vendor) untuk mem-build pada paket lama. |
menghasilkan | Menunjukkan metode antarmuka yang menampilkan nilai ke klien. Untuk menampilkan satu nilai non-primitif, atau lebih dari satu nilai, fungsi callback sinkron akan dibuat. |
antarmuka | Kumpulan metode dan jenis. Diterjemahkan menjadi class di C++ atau Java. Semua metode dalam antarmuka dipanggil dalam arah yang sama: proses klien memanggil metode yang diimplementasikan oleh proses server. |
sekali jalan | Jika diterapkan ke metode HIDL, menunjukkan bahwa metode tidak menampilkan nilai dan tidak memblokir. |
paket | Kumpulan antarmuka dan jenis data yang berbagi versi. |
passthrough | Mode HIDL dengan server adalah library bersama, yang di-dlopen oleh klien. Dalam mode passthrough, klien dan server adalah proses yang sama, tetapi
codebase-nya terpisah. Hanya digunakan untuk memasukkan codebase lama ke dalam model HIDL.
Lihat juga Binderized. |
server | Proses yang mengimplementasikan metode antarmuka. Lihat juga passthrough. |
transportasi | Infrastruktur HIDL yang memindahkan data antara server dan klien. |
version | Versi paket. Terdiri dari dua bilangan bulat, utama dan minor. Penambahan versi minor dapat menambahkan (tetapi tidak mengubah) jenis dan metode. |
Desain HIDL
Tujuan HIDL adalah agar framework Android dapat diganti tanpa harus
mem-build ulang HAL. HAL dibuat oleh vendor atau pembuat SOC dan dimasukkan ke dalam
partisi /vendor
di perangkat, sehingga framework Android, dalam
partisinya sendiri, dapat diganti dengan OTA tanpa mengompilasi ulang HAL.
Desain HIDL menyeimbangkan masalah berikut:
- Interoperabilitas. Buat antarmuka yang dapat dioperasikan secara andal antara proses yang dapat dikompilasi dengan berbagai arsitektur, toolchain, dan konfigurasi build. Antarmuka HIDL diberi versi dan tidak dapat diubah setelah dipublikasikan.
- Efisiensi. HIDL mencoba meminimalkan jumlah operasi salin. Data yang ditentukan HIDL dikirim ke kode C++ dalam struktur data tata letak standar C++ yang dapat digunakan tanpa mengekstrak. HIDL juga menyediakan antarmuka memori bersama dan, karena RPC pada dasarnya agak lambat, HIDL mendukung dua cara untuk mentransfer data tanpa menggunakan panggilan RPC: memori bersama dan Antrean Pesan Cepat (FMQ).
- Intuitif. HIDL menghindari masalah kepemilikan memori yang rumit dengan
hanya menggunakan parameter
in
untuk RPC (lihat Android Interface Definition Language (AIDL)); nilai yang tidak dapat ditampilkan secara efisien dari metode ditampilkan melalui fungsi callback. Meneruskan data ke HIDL untuk transfer atau menerima data dari HIDL tidak akan mengubah kepemilikan data—kepemilikan selalu tetap ada pada fungsi panggilan. Data hanya perlu dipertahankan selama durasi fungsi yang dipanggil dan dapat dihancurkan segera setelah fungsi yang dipanggil ditampilkan.
Menggunakan mode passthrough
Untuk mengupdate perangkat yang menjalankan versi Android sebelumnya ke Android O, Anda dapat menggabungkan HAL konvensional (dan lama) dalam antarmuka HIDL baru yang menyalurkan HAL dalam mode binderized dan proses yang sama (passthrough). Penggabungan ini transparan untuk HAL dan framework Android.
Mode passthrough hanya tersedia untuk klien dan implementasi C++. Perangkat yang menjalankan Android versi sebelumnya tidak memiliki HAL yang ditulis dalam Java, sehingga HAL Java secara inheren di-binder.
File header passthrough
Saat file .hal
dikompilasi, hidl-gen
menghasilkan
file header passthrough tambahan BsFoo.h
selain header
yang digunakan untuk komunikasi binder; header ini menentukan fungsi yang akan
dlopen
. Karena HAL passthrough berjalan dalam proses yang sama dengan
tempatnya dipanggil, dalam sebagian besar kasus, metode passthrough dipanggil oleh panggilan
fungsi langsung (thread yang sama). Metode oneway
berjalan di thread-nya sendiri
karena tidak dimaksudkan untuk menunggu HAL memprosesnya (ini berarti HAL
yang menggunakan metode oneway
dalam mode passthrough harus aman untuk thread).
Dengan IFoo.hal
, BsFoo.h
menggabungkan metode yang dihasilkan
HIDL untuk menyediakan fitur tambahan (seperti membuat transaksi
oneway
berjalan di thread lain). File ini mirip dengan
BpFoo.h
, tetapi alih-alih meneruskan panggilan IPC menggunakan binder, fungsi yang diinginkan langsung dipanggil. Implementasi HAL mendatang
dapat menyediakan beberapa implementasi, seperti HAL FooFast dan
HAL FooAccurate. Dalam kasus tersebut, file untuk setiap implementasi tambahan akan
dibuat (mis., PTFooFast.cpp
dan
PTFooAccurate.cpp
).
Melakukan binderisasi HAL passthrough
Anda dapat meng-binderkan implementasi HAL yang mendukung mode passthrough. Dengan antarmuka HAL a.b.c.d@M.N::IFoo
, dua paket akan dibuat:
a.b.c.d@M.N::IFoo-impl
. Berisi implementasi HAL dan mengekspos fungsiIFoo* HIDL_FETCH_IFoo(const char* name)
. Di perangkat lama, paket ini di-dlopen
dan implementasinya dibuat instance-nya menggunakanHIDL_FETCH_IFoo
. Anda dapat membuat kode dasar menggunakanhidl-gen
dan-Lc++-impl
serta-Landroidbp-impl
.a.b.c.d@M.N::IFoo-service
. Membuka HAL passthrough dan mendaftarkan dirinya sebagai layanan binderized, sehingga implementasi HAL yang sama dapat digunakan sebagai passthrough dan binderized.
Dengan jenis IFoo
, Anda dapat memanggil sp<IFoo>
IFoo::getService(string name, bool getStub)
untuk mendapatkan akses ke instance
IFoo
. Jika getStub
bernilai benar, getService
akan mencoba membuka HAL hanya dalam mode passthrough. Jika getStub
salah, getService
akan mencoba menemukan layanan binderized; jika gagal, getService
akan mencoba menemukan layanan passthrough. Parameter getStub
tidak boleh digunakan kecuali di
defaultPassthroughServiceImplementation
. (Perangkat yang diluncurkan dengan
Android O adalah perangkat yang sepenuhnya di-binder, sehingga membuka layanan dalam mode passthrough
tidak diizinkan.)
Tata bahasa HIDL
Secara desain, bahasa HIDL mirip dengan C (tetapi tidak menggunakan preprosesor
C). Semua tanda baca yang tidak dijelaskan di bawah (selain penggunaan =
dan |
yang jelas) adalah bagian dari tata bahasa.
Catatan: Untuk mengetahui detail tentang gaya kode HIDL, lihat Panduan Gaya Kode.
/** */
menunjukkan komentar dokumentasi. Ini hanya dapat diterapkan ke deklarasi nilai enum, metode, kolom, dan jenis./* */
menunjukkan komentar multibaris.//
menunjukkan komentar ke akhir baris. Selain//
, baris baru sama dengan spasi kosong lainnya.- Dalam contoh tata bahasa di bawah, teks dari
//
hingga akhir baris bukan bagian dari tata bahasa, tetapi merupakan komentar pada tata bahasa. [empty]
berarti istilah tersebut boleh kosong.?
yang mengikuti literal atau istilah berarti bersifat opsional....
menunjukkan urutan yang berisi nol atau beberapa item dengan tanda baca pemisah seperti yang ditunjukkan. Tidak ada argumen variadik di HIDL.- Koma memisahkan elemen urutan.
- Titik koma mengakhiri setiap elemen, termasuk elemen terakhir.
- UPPERCASE adalah nonterminal.
italics
adalah keluarga token sepertiinteger
atauidentifier
(aturan penguraian C standar).constexpr
adalah ekspresi konstanta gaya C (seperti1 + 1
dan1L << 3
).import_name
adalah nama paket atau antarmuka, yang memenuhi syarat seperti yang dijelaskan dalam Pembuatan Versi Hidl.words
huruf kecil adalah token literal.
Contoh:
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr