Bahasa definisi antarmuka HAL atau HIDL adalah bahasa deskripsi antarmuka (IDL) untuk menentukan antarmuka antara HAL dan penggunanya. HIDL memungkinkan menentukan jenis dan panggilan metode, dikumpulkan ke dalam antarmuka dan paket. Lebih luas lagi, HIDL adalah sistem untuk berkomunikasi antar basis kode yang dapat dikompilasi secara mandiri. Sejak Android 10, HIDL sudah tidak digunakan lagi dan Android bermigrasi untuk menggunakan AIDL di mana saja.
HIDL dimaksudkan untuk digunakan untuk komunikasi antar proses (IPC). HAL yang dibuat dengan HDL disebut HAL yang di-binder karena mereka dapat berkomunikasi dengan lapisan arsitektur lain menggunakan panggilan binder inter-process communication (IPC). HAL yang di-binder berjalan dalam proses terpisah dari klien yang menggunakannya. Untuk pustaka yang harus ditautkan ke suatu proses, mode passthrough juga tersedia (tidak didukung di Java).
HIDL menentukan struktur data dan tanda tangan metode, diatur dalam antarmuka (mirip dengan kelas) yang dikumpulkan ke dalam paket. Sintaks HIDL terlihat familiar bagi pemrogram C++ dan Java, tetapi dengan rangkaian kata kunci yang berbeda. HIDL juga menggunakan anotasi gaya Java.
Terminologi
Bagian ini menggunakan istilah terkait HIDL berikut:
dijilid | Menunjukkan HIDL sedang digunakan untuk panggilan prosedur jarak jauh antar proses, diimplementasikan melalui mekanisme mirip Binder. Lihat juga passthrough . |
---|---|
panggilan balik, asinkron | Antarmuka dilayani oleh pengguna HAL, diteruskan ke HAL (menggunakan metode HIDL), dan dipanggil oleh HAL untuk mengembalikan data kapan saja. |
panggilan balik, sinkron | Mengembalikan data dari implementasi metode HIDL server ke klien. Tidak digunakan untuk metode yang mengembalikan nilai kosong atau primitif tunggal. |
klien | Proses yang memanggil metode antarmuka tertentu. Proses kerangka kerja HAL atau Android mungkin merupakan klien dari satu antarmuka dan server dari yang lain. Lihat juga passthrough . |
memanjang | Menunjukkan antarmuka yang menambahkan metode dan/atau tipe ke antarmuka lain. Antarmuka hanya dapat memperluas satu antarmuka lainnya. Dapat digunakan untuk peningkatan versi minor dalam nama paket yang sama atau untuk paket baru (misalnya ekstensi vendor) untuk membangun paket lama. |
menghasilkan | Menunjukkan metode antarmuka yang mengembalikan nilai ke klien. Untuk mengembalikan satu nilai non-primitif, atau lebih dari satu nilai, fungsi callback sinkron dibuat. |
antarmuka | Koleksi metode dan jenis. Diterjemahkan ke dalam kelas di C++ atau Java. Semua metode dalam antarmuka dipanggil ke arah yang sama: proses klien memanggil metode yang diterapkan oleh proses server. |
SATU ARAH | Saat diterapkan ke metode HIDL, menunjukkan bahwa metode tidak mengembalikan nilai dan tidak memblokir. |
kemasan | Kumpulan antarmuka dan tipe data berbagi versi. |
melewati | Mode dlopen di mana server adalah perpustakaan bersama, dibuka oleh klien. Dalam mode passthrough, klien dan server adalah proses yang sama tetapi basis kode terpisah. Digunakan hanya untuk membawa basis kode lama ke dalam model HIDL. Lihat juga Binderized . |
server | Proses yang mengimplementasikan metode antarmuka. Lihat juga passthrough . |
mengangkut | Infrastruktur HIDL yang memindahkan data antara server dan klien. |
Versi: kapan | Versi sebuah paket. Terdiri dari dua bilangan bulat, mayor dan minor. Peningkatan versi kecil dapat menambahkan (namun tidak mengubah) jenis dan metode. |
desain HIDL
Tujuan HIDL adalah agar framework Android dapat diganti tanpa harus membangun ulang HAL. HAL akan dibuat oleh vendor atau pembuat SOC dan diletakkan di partisi /vendor
pada perangkat, memungkinkan kerangka kerja Android, di partisinya sendiri, diganti dengan OTA tanpa mengkompilasi ulang HAL.
Desain HIDL menyeimbangkan perhatian berikut:
- Interoperabilitas . Buat antarmuka interoperabilitas andal antara proses yang dapat dikompilasi dengan berbagai arsitektur, rantai alat, dan konfigurasi build. Antarmuka HIDL memiliki versi dan tidak dapat diubah setelah dipublikasikan.
- Efisiensi . HIDL mencoba meminimalkan jumlah operasi penyalinan. Data yang ditentukan HIDL dikirim ke kode C++ dalam struktur data tata letak standar C++ yang dapat digunakan tanpa membongkar. 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 Fast Message Queue (FMQ).
- Intuitif . HIDL menghindari masalah pelik kepemilikan memori dengan hanya
in
parameter untuk RPC (lihat Android Interface Definition Language (AIDL) ); nilai yang tidak dapat dikembalikan secara efisien dari metode dikembalikan melalui fungsi callback. Baik meneruskan data ke HIDL untuk transfer maupun menerima data dari HIDL tidak mengubah kepemilikan data—kepemilikan selalu tetap dengan fungsi pemanggilan. Data perlu bertahan hanya selama durasi fungsi yang dipanggil dan dapat dimusnahkan segera setelah fungsi yang dipanggil kembali.
Menggunakan mode passthrough
Untuk mengupdate perangkat yang menjalankan Android versi sebelumnya ke Android O, Anda dapat menggabungkan HAL konvensional (dan lama) dalam antarmuka HIDL baru yang melayani HAL dalam mode binderized dan proses yang sama (passthrough). Pembungkusan ini transparan untuk HAL dan framework Android.
Mode passthrough hanya tersedia untuk klien dan implementasi C++. Perangkat yang menjalankan versi Android sebelumnya tidak memiliki HAL yang ditulis dalam Java, sehingga Java HAL secara inheren terikat.
Lewati file header
Saat file .hal
dikompilasi, hidl-gen
menghasilkan file header passthrough tambahan BsFoo.h
selain header yang digunakan untuk komunikasi pengikat; tajuk ini mendefinisikan fungsi yang akan dlopen
. Karena HAL passthrough berjalan dalam proses yang sama di mana mereka dipanggil, dalam banyak kasus metode passthrough dipanggil oleh pemanggilan fungsi langsung (thread yang sama). metode satu arah berjalan di oneway
sendiri karena tidak dimaksudkan untuk menunggu HAL memprosesnya (ini berarti setiap HAL yang menggunakan metode oneway
dalam mode passthrough harus aman untuk thread).
Diberikan IFoo.hal
, BsFoo.h
membungkus metode yang dihasilkan HIDL untuk menyediakan fitur tambahan (seperti membuat transaksi oneway
berjalan di utas lain). File ini mirip dengan BpFoo.h
, namun alih-alih meneruskan panggilan IPC menggunakan binder, fungsi yang diinginkan langsung dipanggil. Implementasi HAL di masa mendatang dapat menyediakan beberapa implementasi, seperti FooFast HAL dan FooAccurate HAL. Dalam kasus tersebut, file untuk setiap implementasi tambahan akan dibuat (misalnya, PTFooFast.cpp
dan PTFooAccurate.cpp
).
Mengikat passthrough HAL
Anda dapat mengikat implementasi HAL yang mendukung mode passthrough. Diberi antarmuka HAL abcd@MN::IFoo
, dua paket dibuat:
-
abcd@MN::IFoo-impl
. Berisi implementasi HAL dan memperlihatkan fungsiIFoo* HIDL_FETCH_IFoo(const char* name)
. Pada perangkat lawas, paket iniHIDL_FETCH_IFoo
dlopen
Anda dapat membuat kode dasar menggunakanhidl-gen
dan-Lc++-impl
dan-Landroidbp-impl
. -
abcd@MN::IFoo-service
. Membuka HAL passthrough dan mendaftarkan dirinya sebagai layanan yang di-binder, memungkinkan implementasi HAL yang sama untuk digunakan baik sebagai passthrough maupun yang di-binder.
Diberikan tipe IFoo
, Anda dapat memanggil sp<IFoo> IFoo::getService(string name, bool getStub)
untuk mendapatkan akses ke instance IFoo
. Jika getStub
benar, getService
mencoba membuka HAL hanya dalam mode passthrough. Jika getStub
salah, getService
mencoba menemukan layanan yang di-binder; jika gagal, ia kemudian mencoba menemukan layanan passthrough. Parameter getStub
tidak boleh digunakan kecuali di defaultPassthroughServiceImplementation
. (Perangkat yang diluncurkan dengan Android O adalah perangkat yang sepenuhnya terikat, 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 detail tentang gaya kode HIDL, lihat Panduan Gaya Kode .
-
/** */
menunjukkan komentar dokumentasi. Ini hanya dapat diterapkan untuk deklarasi tipe, metode, bidang, dan nilai enum. -
/* */
menunjukkan komentar multibaris. -
//
menunjukkan komentar di akhir baris. Selain//
, baris baru sama dengan spasi putih lainnya. - Pada contoh tata bahasa di bawah ini, teks dari
//
hingga akhir baris bukan bagian dari tata bahasa melainkan merupakan komentar pada tata bahasa. -
[empty]
berarti istilah itu boleh kosong. -
?
mengikuti literal atau istilah berarti itu opsional. -
...
menunjukkan urutan yang berisi nol atau lebih item dengan tanda baca terpisah seperti yang ditunjukkan. Tidak ada argumen variadik dalam HIDL. - Koma memisahkan elemen urutan.
- Titik koma mengakhiri setiap elemen, termasuk elemen terakhir.
- UPPERCASE adalah nonterminal.
-
italics
adalah keluarga token sepertiinteger
atauidentifier
(aturan parsing C standar). -
constexpr
adalah ekspresi konstanta gaya C (seperti1 + 1
dan1L << 3
). -
import_name
adalah nama paket atau antarmuka, memenuhi syarat seperti yang dijelaskan dalam HIDL Versioning . - Kata-
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