TERSEMBUNYI

Bahasa definisi antarmuka HAL atau HIDL adalah bahasa deskripsi antarmuka (IDL) untuk menentukan antarmuka antara HAL dan penggunanya. HIDL memungkinkan menentukan tipe dan pemanggilan metode, dikumpulkan ke dalam antarmuka dan paket. Secara lebih luas, HIDL adalah sistem untuk berkomunikasi antar basis kode yang dapat dikompilasi secara independen. Mulai Android 10, HIDL 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 diikat karena mereka dapat berkomunikasi dengan lapisan arsitektur lain menggunakan panggilan komunikasi antar-proses (IPC) pengikat. HAL yang diikat dijalankan dalam proses terpisah dari klien yang menggunakannya. Untuk perpustakaan yang harus ditautkan ke suatu proses, mode passthrough juga tersedia (tidak didukung di Java).

HIDL menentukan struktur data dan tanda tangan metode, disusun dalam antarmuka (mirip dengan kelas) yang dikumpulkan ke dalam paket. Sintaks HIDL terlihat familier bagi pemrogram C++ dan Java, tetapi dengan kumpulan kata kunci yang berbeda. HIDL juga menggunakan anotasi gaya Java.

Terminologi

Bagian ini menggunakan istilah terkait HIDL berikut:

diikat Menunjukkan HIDL digunakan untuk panggilan prosedur jarak jauh antar proses, diimplementasikan melalui mekanisme mirip Binder. Lihat juga lewatan .
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 kekosongan atau nilai primitif tunggal.
klien Proses yang memanggil metode antarmuka tertentu. Proses kerangka kerja HAL atau Android mungkin merupakan klien dari satu antarmuka dan server dari antarmuka lainnya. Lihat juga lewatan .
meluas Menunjukkan antarmuka yang menambahkan metode dan/atau tipe ke antarmuka lain. Sebuah antarmuka hanya dapat memperluas satu antarmuka lainnya. Dapat digunakan untuk penambahan versi minor pada 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 panggilan balik sinkron dihasilkan.
antarmuka Kumpulan metode dan tipe. Diterjemahkan ke dalam kelas dalam C++ atau Java. Semua metode dalam antarmuka dipanggil dalam arah yang sama: proses klien memanggil metode yang diimplementasikan oleh proses server.
SATU ARAH Ketika diterapkan pada metode HIDL, menunjukkan bahwa metode tersebut tidak mengembalikan nilai dan tidak memblokir.
kemasan Kumpulan antarmuka dan tipe data yang berbagi versi.
melewati Mode HIDL di mana server adalah perpustakaan bersama, dlopen oleh klien. Dalam mode passthrough, klien dan server adalah proses yang sama tetapi basis kode terpisah. Hanya digunakan untuk membawa basis kode lama ke dalam model HIDL. Lihat juga Diikat .
server Proses yang mengimplementasikan metode antarmuka. Lihat juga lewatan .
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 menambah (tetapi tidak mengubah) jenis dan metode.

desain HIDL

Tujuan HIDL adalah agar framework Android dapat diganti tanpa harus membangun kembali HAL. HAL akan dibuat oleh vendor atau pembuat SOC dan dimasukkan ke dalam partisi /vendor pada perangkat, memungkinkan kerangka Android, di partisinya sendiri, diganti dengan OTA tanpa mengkompilasi ulang HAL.

Desain HIDL menyeimbangkan kekhawatiran berikut:

  • Interoperabilitas . Buat antarmuka yang dapat dioperasikan secara andal antar 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 dikirimkan 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 tentang 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 panggilan balik. Baik meneruskan data ke HIDL untuk ditransfer maupun menerima data dari HIDL tidak mengubah kepemilikan data—kepemilikan selalu tetap pada fungsi pemanggil. Data hanya perlu disimpan selama fungsi yang dipanggil dan dapat dimusnahkan segera setelah fungsi yang dipanggil kembali.

Menggunakan mode passthrough

Untuk memperbarui perangkat yang menjalankan Android versi sebelumnya ke Android O, Anda dapat menggabungkan HAL konvensional (dan lama) dalam antarmuka HIDL baru yang menyajikan HAL dalam mode pengikatan dan proses yang sama (passthrough). Pembungkusan ini transparan untuk kerangka HAL dan Android.

Mode passthrough hanya tersedia untuk klien dan implementasi C++. Perangkat yang menjalankan Android versi lebih lama tidak memiliki HAL yang ditulis dalam Java, sehingga HAL Java pada dasarnya bersifat binder.

Ketika file .hal dikompilasi, hidl-gen menghasilkan file header passthrough tambahan BsFoo.h selain header yang digunakan untuk komunikasi pengikat; header ini mendefinisikan fungsi yang akan di dlopen . Karena HAL passthrough dijalankan dalam proses yang sama saat mereka dipanggil, dalam banyak kasus metode passthrough dipanggil dengan pemanggilan fungsi langsung (thread yang sama). metode oneway berjalan di threadnya sendiri karena tidak dimaksudkan untuk menunggu HAL memprosesnya (ini berarti HAL apa pun yang menggunakan metode oneway dalam mode passthrough harus aman untuk thread).

Diberikan 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 , namun alih-alih meneruskan panggilan IPC menggunakan binder, fungsi yang diinginkan langsung dipanggil. Implementasi HAL di masa depan mungkin 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 HAL passthrough

Anda dapat mengikat implementasi HAL yang mendukung mode passthrough. Dengan adanya antarmuka HAL abcd@MN::IFoo , dua paket dibuat:

  • abcd@MN::IFoo-impl . Berisi implementasi HAL dan mengekspos fungsi IFoo* HIDL_FETCH_IFoo(const char* name) . Pada perangkat lama, paket ini dlopen dan implementasinya dibuat menggunakan HIDL_FETCH_IFoo . Anda dapat membuat kode dasar menggunakan hidl-gen dan -Lc++-impl dan -Landroidbp-impl .
  • abcd@MN::IFoo-service . Membuka HAL passthrough dan mendaftarkan dirinya sebagai layanan yang diikat, memungkinkan implementasi HAL yang sama untuk digunakan sebagai passthrough dan diikat.

Mengingat 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 terikat; jika gagal, ia kemudian mencoba mencari layanan passthrough. Parameter getStub tidak boleh digunakan kecuali di defaultPassthroughServiceImplementation . (Perangkat yang diluncurkan dengan Android O adalah perangkat yang sepenuhnya terikat, jadi membuka layanan dalam mode passthrough tidak diperbolehkan.)

tata bahasa HIDL

Secara desain, bahasa HIDL mirip dengan C (tetapi tidak menggunakan praprosesor C). Semua tanda baca yang tidak dijelaskan di bawah (selain penggunaan = dan | ) adalah bagian dari tata bahasa.

Catatan: Untuk detail tentang gaya kode HIDL, lihat Panduan Gaya Kode .

  • /** */ menunjukkan komentar dokumentasi. Ini hanya dapat diterapkan pada deklarasi tipe, metode, bidang, dan nilai enum.
  • /* */ menunjukkan komentar multiline.
  • // menunjukkan komentar di akhir baris. Selain // , baris baru sama dengan spasi lainnya.
  • Pada contoh tata bahasa di bawah, teks dari // hingga akhir baris bukan merupakan bagian dari tata bahasa namun merupakan komentar pada tata bahasa.
  • [empty] berarti istilah tersebut mungkin kosong.
  • ? mengikuti literal atau istilah berarti opsional.
  • ... menunjukkan urutan yang mengandung nol atau lebih item dengan tanda baca pemisah seperti yang ditunjukkan. Tidak ada argumen variadik di HIDL.
  • Elemen urutan yang dipisahkan koma.
  • Titik koma mengakhiri setiap elemen, termasuk elemen terakhir.
  • UPPERCASE adalah nonterminal.
  • italics adalah keluarga token seperti integer atau identifier (aturan parsing standar C).
  • constexpr adalah ekspresi konstan gaya C (seperti 1 + 1 dan 1L << 3 ).
  • import_name adalah nama paket atau antarmuka, yang memenuhi syarat seperti yang dijelaskan dalam Versi HIDL .
  • words dengan huruf kecil adalah tanda 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