C++ HIDL

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

Halaman di bagian ini menjelaskan implementasi C++ antarmuka HIDL, termasuk detail tentang file yang dibuat secara otomatis dari file .hal HIDL oleh compiler hidl-gen, cara file ini dikemas, dan cara mengintegrasikan file ini dengan kode C++ yang menggunakannya.

Implementasi klien dan 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 menampilkan hasil (jika diperlukan).

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

Gambar 1. Progres pengembangan untuk HAL lama.

Membuat klien HAL

Mulai dengan menyertakan library HAL dalam makefile:

  • Buat: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • Soong: 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 dan telah membuat file makefile untuk HAL menggunakan -Lmakefile atau -Landroidbp di hidl-gen (./hardware/interfaces/update-makefiles.sh melakukannya untuk file HAL internal dan merupakan referensi yang baik). Saat mentransfer HAL dari libhardware, Anda dapat melakukan banyak pekerjaan ini dengan mudah menggunakan c2hal.

Untuk membuat file yang diperlukan guna menerapkan HAL:

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 dengan 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 ekstensi HAL lain, HAL dasar harus digunakan untuk memberi nama biner ini. Misalnya, implementasi android.hardware.graphics.mapper@2.1 harus masih 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 meng-upcast implementasi.

Selanjutnya, isi stub dengan fungsi dan siapkan daemon. Contoh kode daemon (mendukung passthrough):

#include <hidl/LegacySupport.h>

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

defaultPassthroughServiceImplementation memanggil dlopen() untuk library -impl yang disediakan dan menyediakannya sebagai layanan binderized. Contoh kode daemon (untuk layanan binderized 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 never exceeds
    // 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 dapat berada di mana saja. Sepolicy untuk class HAL tertentu adalah atribut hal_<module> (misalnya, hal_nfc). Atribut ini harus diterapkan ke daemon yang menjalankan HAL tertentu (jika proses yang sama menayangkan beberapa HAL, beberapa atribut dapat diterapkan ke HAL tersebut).