HIDL C++

Android O merancang ulang OS Android untuk mendefinisikan antarmuka yang jelas antara platform Android yang tidak bergantung pada perangkat dan kode khusus perangkat dan vendor. Android sudah mendefinisikan banyak antarmuka seperti itu dalam bentuk antarmuka HAL, yang didefinisikan sebagai header C di hardware/libhardware . HIDL menggantikan antarmuka HAL ini dengan antarmuka yang stabil dan berversi, yang dapat berupa antarmuka HIDL sisi klien dan server dalam C++ (dijelaskan di bawah) atau Java .

Halaman-halaman di bagian ini menjelaskan implementasi C++ antarmuka HIDL, termasuk detail tentang file yang dibuat secara otomatis dari file .hal .hal oleh kompiler hidl-gen , bagaimana file-file ini dikemas, dan bagaimana mengintegrasikan file-file ini dengan kode C++ yang menggunakan mereka.

Implementasi klien & server

Antarmuka HIDL memiliki implementasi klien dan server:

  • Klien antarmuka HIDL adalah kode yang menggunakan antarmuka dengan memanggil metode di atasnya.
  • Server adalah implementasi antarmuka HIDL yang menerima panggilan dari klien dan mengembalikan hasil (jika perlu).

Dalam transisi dari libhardware HAL ke HIDL HAL, implementasi HAL menjadi server dan proses pemanggilan ke HAL menjadi klien. Implementasi default dapat melayani HAL passthrough dan binder, dan dapat berubah seiring waktu:

Gambar 1. Perkembangan pengembangan HAL warisan.

Membuat klien HAL

Mulailah dengan memasukkan perpustakaan HAL di makefile:

  • Buat: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • Segera: shared_libs: [ …, android.hardware.nfc@1.0 ]

Selanjutnya, sertakan file header HAL:

#include <android/hardware/nfc/1.0/IFoo.h>
…
// in code:
sp<IFoo> client = IFoo::getService();
client->doThing();

Membuat server HAL

Untuk membuat implementasi HAL, Anda harus memiliki file .hal yang mewakili HAL Anda dan telah membuat makefile untuk HAL Anda menggunakan -Lmakefile atau -Landroidbp pada hidl-gen ( ./hardware/interfaces/update-makefiles.sh melakukan ini untuk file HAL internal dan merupakan referensi yang baik). Saat mentransfer melalui HAL dari libhardware , Anda dapat melakukan banyak pekerjaan ini dengan mudah menggunakan c2hal.

Untuk membuat file yang diperlukan untuk mengimplementasikan HAL Anda:

PACKAGE=android.hardware.nfc@1.0
LOC=hardware/interfaces/nfc/1.0/default/
m -j hidl-gen
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE

Agar HAL bekerja dalam mode passthrough, Anda harus memiliki fungsi HIDL_FETCH_IModuleName yang berada di /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).so di mana OPTIONAL_IDENTIFIER adalah string yang mengidentifikasi implementasi passthrough. Persyaratan mode passthrough dipenuhi secara otomatis oleh perintah di atas, yang juga membuat target android.hardware.nfc@1.0-impl , tetapi ekstensi apa pun dapat digunakan. Misalnya android.hardware.nfc@1.0-impl-foo menggunakan -foo untuk membedakan dirinya.

Jika HAL adalah versi minor atau perpanjangan dari HAL lain, basis HAL harus digunakan untuk menamai biner ini. Misalnya, implementasi android.hardware.graphics.mapper@2.1 harus tetap dalam biner yang disebut android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER ) . Biasanya, OPTIONAL_IDENTIFIER di sini akan menyertakan versi HAL yang sebenarnya. Dengan memberi nama biner seperti ini, klien 2.0 dapat mengambilnya secara langsung, dan klien 2.1 dapat meningkatkan implementasinya.

Selanjutnya, isi stub dengan fungsionalitas dan atur daemon. Contoh kode daemon (mendukung passthrough):

#include <hidl/LegacySupport.h>

int main(int /* argc */, char* /* argv */ []) {
    return defaultPassthroughServiceImplementation<INfc>("nfc");
}

defaultPassthroughServiceImplementation akan dlopen() perpustakaan -impl yang disediakan dan menyediakannya sebagai layanan yang diikat. Contoh kode daemon (untuk layanan binder murni):

int main(int /* argc */, char* /* argv */ []) {
    // This function must be called before you join to ensure the proper
    // number of threads are created. The threadpool will never exceed
    // size one because of this call.
    ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);

    sp<INfc> nfc = new Nfc();
    const status_t status = nfc->registerAsService();
    if (status != ::android::OK) {
        return 1; // or handle error
    }

    // Adds this thread to the threadpool, resulting in one total
    // thread in the threadpool. We could also do other things, but
    // would have to specify 'false' to willJoin in configureRpcThreadpool.
    ::android::hardware::joinRpcThreadpool();
    return 1; // joinRpcThreadpool should never return
}

Daemon ini biasanya berada di $PACKAGE + "-service-suffix" (misalnya, android.hardware.nfc@1.0-service ), tetapi bisa di mana saja. Kebijakan untuk kelas HAL tertentu adalah atribut hal_ hal_<module> (misalnya, hal_nfc) . Atribut ini harus diterapkan ke daemon yang menjalankan HAL tertentu (jika proses yang sama melayani beberapa HAL, beberapa atribut dapat diterapkan padanya).