Antarmuka

Setiap antarmuka yang didefinisikan dalam paket HIDL memiliki kelas C++ yang dibuat secara otomatis di dalam namespace paketnya. Klien dan server menangani antarmuka dengan cara yang berbeda:

  • Server mengimplementasikan antarmuka.
  • Klien memanggil metode pada antarmuka.

Antarmuka dapat didaftarkan berdasarkan nama oleh server atau diteruskan sebagai parameter ke metode yang ditentukan HIDL. Misalnya, kode kerangka kerja dapat melayani antarmuka untuk menerima pesan asinkron dari HAL dan meneruskan antarmuka tersebut langsung ke HAL tanpa mendaftarkannya.

Implementasi server

Server yang mengimplementasikan antarmuka IFoo harus menyertakan file header IFoo yang dibuat secara otomatis:

#include <android/hardware/samples/1.0/IFoo.h>

Header secara otomatis diekspor oleh perpustakaan bersama antarmuka IFoo untuk ditautkan. Contoh IFoo.hal :

// IFoo.hal
interface IFoo {
    someMethod() generates (vec<uint32_t>);
    ...
}

Contoh kerangka implementasi server antarmuka IFoo:

// From the IFoo.h header
using android::hardware::samples::V1_0::IFoo;

class FooImpl : public IFoo {
    Return<void> someMethod(foo my_foo, someMethod_cb _cb) {
        vec<uint32_t> return_data;
        // Compute return_data
        _cb(return_data);
        return Void();
    }
    ...
};

Untuk membuat implementasi antarmuka server tersedia bagi klien, Anda dapat:

  1. Daftarkan implementasi antarmuka dengan hwservicemanager (lihat detail di bawah),

    ATAU

  2. Teruskan implementasi antarmuka sebagai argumen metode antarmuka (untuk detailnya, lihat Callback asinkron ).

Saat mendaftarkan implementasi antarmuka, proses hwservicemanager melacak antarmuka HIDL terdaftar yang berjalan pada perangkat berdasarkan nama dan versi. Server dapat mendaftarkan implementasi antarmuka HIDL berdasarkan nama dan klien dapat meminta implementasi layanan berdasarkan nama dan versi. Proses ini melayani antarmuka HIDL android.hidl.manager@1.0::IServiceManager .

Setiap file header antarmuka HIDL yang dibuat secara otomatis (seperti IFoo.h ) memiliki metode registerAsService() yang dapat digunakan untuk mendaftarkan implementasi antarmuka dengan hwservicemanager . Satu-satunya argumen yang diperlukan adalah nama implementasi antarmuka karena klien akan menggunakan nama ini untuk mengambil antarmuka dari hwservicemanager nanti:

::android::sp<IFoo> myFoo = new FooImpl();
::android::sp<IFoo> mySecondFoo = new FooAnotherImpl();
status_t status = myFoo->registerAsService();
status_t anotherStatus = mySecondFoo->registerAsService("another_foo");

hwservicemanager memperlakukan kombinasi [package@version::interface, instance_name] sebagai unik untuk mengaktifkan antarmuka berbeda (atau versi berbeda dari antarmuka yang sama) untuk mendaftar dengan nama instance yang identik tanpa konflik. Jika Anda memanggil registerAsService() dengan versi paket, antarmuka, dan nama instance yang sama persis, hwservicemanager akan menghapus referensinya ke layanan yang terdaftar sebelumnya dan menggunakan layanan baru.

Implementasi klien

Sama seperti server, klien harus #include setiap antarmuka yang dirujuknya:

#include <android/hardware/samples/1.0/IFoo.h>

Seorang klien dapat memperoleh antarmuka dengan dua cara:

  • Melalui I<InterfaceName>::getService (melalui hwservicemanager )
  • Melalui metode antarmuka

Setiap file header antarmuka yang dibuat secara otomatis memiliki metode getService statis yang dapat digunakan untuk mengambil instance layanan dari hwservicemanager :

// getService will return nullptr if the service can't be found
sp<IFoo> myFoo = IFoo::getService();
sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");

Sekarang klien memiliki antarmuka IFoo , dan dapat memanggil metode seolah-olah itu adalah implementasi kelas lokal. Pada kenyataannya, implementasi dapat berjalan dalam proses yang sama, proses yang berbeda, atau bahkan pada perangkat lain (dengan HAL remoting). Karena klien memanggil getService pada objek IFoo yang disertakan dari paket versi 1.0 , hwservicemanager mengembalikan implementasi server hanya jika implementasi tersebut kompatibel dengan klien 1.0 . Dalam praktiknya, ini berarti hanya implementasi server dengan versi 1.n (versi x.(y+1) antarmuka yang harus diperluas (mewarisi dari) xy ).

Selain itu, metode castFrom disediakan untuk melakukan transmisi antar antarmuka yang berbeda. Metode ini bekerja dengan melakukan panggilan IPC ke antarmuka jarak jauh untuk memastikan tipe dasarnya sama dengan tipe yang diminta. Jika tipe yang diminta tidak tersedia, maka nullptr dikembalikan.

sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService();
sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);

Panggilan balik asinkron

Banyak implementasi HAL yang ada menggunakan perangkat keras asinkron, yang berarti mereka memerlukan cara asinkron untuk memberi tahu klien tentang peristiwa baru yang telah terjadi. Antarmuka HIDL dapat digunakan sebagai panggilan balik asinkron karena fungsi antarmuka HIDL dapat menggunakan objek antarmuka HIDL sebagai parameter.

Contoh file antarmuka IFooCallback.hal :

package android.hardware.samples@1.0;
interface IFooCallback {
    sendEvent(uint32_t event_id);
    sendData(vec<uint8_t> data);
}

Contoh metode baru di IFoo yang menggunakan parameter IFooCallback :

package android.hardware.samples@1.0;
interface IFoo {
    struct Foo {
       int64_t someValue;
       handle myHandle;
    };

    someMethod(Foo foo) generates (int32_t ret);
    anotherMethod() generates (vec<uint32_t>);
    registerCallback(IFooCallback callback);
};

Klien yang menggunakan antarmuka IFoo adalah server antarmuka IFooCallback ; ini menyediakan implementasi IFooCallback :

class FooCallback : public IFooCallback {
    Return<void> sendEvent(uint32_t event_id) {
        // process the event from the HAL
    }
    Return<void> sendData(const hidl_vec<uint8_t>& data) {
        // process data from the HAL
    }
};

Itu juga dapat dengan mudah meneruskannya ke instance antarmuka IFoo yang ada:

sp<IFooCallback> myFooCallback = new FooCallback();
myFoo.registerCallback(myFooCallback);

Server yang mengimplementasikan IFoo menerima ini sebagai objek sp<IFooCallback> . Itu dapat menyimpan panggilan balik, dan memanggil kembali ke klien kapan pun ia ingin menggunakan antarmuka ini.

Penerima kematian

Karena implementasi layanan dapat berjalan dalam proses yang berbeda, proses yang mengimplementasikan antarmuka dapat mati sementara klien tetap hidup. Setiap panggilan pada objek antarmuka yang dihosting dalam proses yang telah mati akan gagal dengan kesalahan transport ( isOK() akan menghasilkan nilai salah). Satu-satunya cara untuk memulihkan kegagalan tersebut adalah dengan meminta layanan baru dengan memanggil I<InterfaceName>::getService() . Ini hanya berfungsi jika proses yang mogok telah dimulai ulang dan mendaftarkan ulang layanannya ke servicemanager (yang umumnya berlaku untuk implementasi HAL).

Daripada menangani hal ini secara reaktif, klien antarmuka juga dapat mendaftarkan penerima kematian untuk mendapatkan pemberitahuan ketika layanan mati. Untuk mendaftar pemberitahuan tersebut pada antarmuka IFoo yang diambil, klien dapat melakukan hal berikut:

foo->linkToDeath(recipient, 1481 /* cookie */);

Parameter recipient harus merupakan implementasi antarmuka android::hardware::hidl_death_recipient yang disediakan oleh HIDL, yang berisi metode tunggal serviceDied() yang akan dipanggil dari thread di threadpool RPC ketika proses yang menghosting antarmuka tersebut mati:

class MyDeathRecipient : public android::hardware::hidl_death_recipient {
    virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) {
       // Deal with the fact that the service died
    }
}

Parameter cookie berisi cookie yang diteruskan dengan linkToDeath() , sedangkan parameter who berisi penunjuk lemah ke objek yang mewakili layanan di klien. Dengan contoh panggilan yang diberikan di atas, cookie sama dengan 1481, dan who sama dengan foo .

Dimungkinkan juga untuk membatalkan pendaftaran penerima kematian setelah mendaftarkannya:

foo->unlinkToDeath(recipient);