MENYEMBUNYIKAN C++

Android O merancang ulang OS Android untuk menentukan 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 berversi yang stabil, yang dapat berupa antarmuka HIDL sisi klien dan server dalam C++ (dijelaskan di bawah) atau Java .

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

Implementasi klien & server

Antarmuka HIDL memiliki implementasi klien dan server:

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

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

Gambar 1. Kemajuan pengembangan HAL lama.

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 sudah membuat makefile untuk HAL Anda menggunakan -Lmakefile atau -Landroidbp di hidl-gen ( ./hardware/interfaces/update-makefiles.sh melakukan ini untuk file HAL internal dan merupakan referensi yang bagus). Saat mentransfer 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 berfungsi 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 , namun 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, HAL dasar harus digunakan untuk memberi nama biner ini. Misalnya, implementasi android.hardware.graphics.mapper@2.1 harus tetap dalam biner bernama android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER ) . Biasanya, OPTIONAL_IDENTIFIER di sini menyertakan versi HAL sebenarnya. Dengan memberi nama biner seperti ini, klien 2.0 dapat mengambilnya secara langsung, dan klien 2.1 dapat melakukan upcast implementasinya.

Selanjutnya, isi stub dengan fungsionalitas dan siapkan 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 pengikat 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 ), namun bisa juga di mana saja. Kebijakan untuk kelas HAL tertentu adalah atribut hal_<module> (misalnya, hal_nfc) . Atribut ini harus diterapkan pada daemon yang menjalankan HAL tertentu (jika proses yang sama melayani beberapa HAL, beberapa atribut dapat diterapkan padanya).