Interfaces

Jede in einem HIDL-Paket definierte Schnittstelle hat eine eigene automatisch generierte C++-Klasse. im Namespace des Pakets enthalten. Clients und Server arbeiten mit Schnittstellen in verschiedene Möglichkeiten:

  • Server implementieren Schnittstellen.
  • Clients rufen Methoden für Schnittstellen auf.

Schnittstellen können entweder vom Server namentlich registriert oder als Parameter zu HIDL-definierten Methoden hinzufügen. Framework-Code kann beispielsweise Schnittstelle, um asynchrone Nachrichten vom HAL zu empfangen und diese Schnittstelle zu übergeben. direkt im HAL, ohne sie zu registrieren.

Serverimplementierung

Ein Server, der die IFoo-Schnittstelle implementiert, muss Folgendes enthalten: IFoo-Headerdatei, die automatisch generiert wurde:

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

Der Header wird automatisch von der gemeinsam genutzten Bibliothek des IFoo-Schnittstelle, die verknüpft werden soll. Beispiel für IFoo.hal:

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

Beispielskelett für eine Serverimplementierung der IFoo-Schnittstelle:

// 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();
    }
    ...
};

Um einem Client die Implementierung einer Serverschnittstelle zur Verfügung zu stellen, müssen Sie kann:

  1. Registrieren Sie die Schnittstellenimplementierung bei der hwservicemanager (siehe Details unten),

    ODER

  2. Übergeben Sie die Schnittstellenimplementierung als Argument eines (für weitere Details siehe Asynchrones Callbacks.

Bei der Registrierung der Schnittstellenimplementierung wird der Parameter Der hwservicemanager-Prozess verfolgt registrierte HIDL-Schnittstellen Name und Version auf dem Gerät ausgeführt werden. Server können eine HIDL-Schnittstelle registrieren. Implementierung nach Name und Kunden können Dienstimplementierungen über den Namen anfordern und Version. Dieser Prozess dient der HIDL-Schnittstelle android.hidl.manager@1.0::IServiceManager

Jede automatisch generierte HIDL-Schnittstellen-Headerdatei (z. B. IFoo.h) verfügt über eine registerAsService()-Methode, die zum Registrieren des mithilfe der hwservicemanager implementieren. Die einzige Das erforderliche Argument ist der Name der Schnittstellenimplementierungen als Clients. Verwenden Sie diesen Namen, um die Schnittstelle aus hwservicemanager abzurufen. später:

::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 behandelt die Kombination aus „[package@version::interface, instance_name]“ muss eindeutig sein, um die Funktion zu aktivieren. verschiedene Schnittstellen (oder verschiedene Versionen derselben Schnittstelle) zu registrieren, mit identischen Instanznamen ohne Konflikte. Wenn Sie registerAsService() mit exakt derselben Paketversion, Schnittstelle und Instanznamen entfernt, verwirft hwservicemanager seinen Verweis auf den registriert und den neuen verwendet.

Client-Implementierung

Genau wie der Server muss ein Client jede Schnittstelle #include. sich auf Folgendes bezieht:

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

Ein Client kann eine Schnittstelle auf zwei Arten abrufen:

  • Bis I<InterfaceName>::getService (über die hwservicemanager)
  • Über eine Schnittstellenmethode

Jede automatisch generierte Schnittstellen-Header-Datei hat einen statischen getService , die zum Abrufen einer Dienstinstanz aus dem hwservicemanager:

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

Jetzt hat der Client eine IFoo-Schnittstelle und kann Methoden aufrufen, wie eine lokale Klassenimplementierung. Tatsächlich wird die Implementierung können im selben, in einem anderen Prozess oder sogar auf einem anderen Gerät ausgeführt werden. (mit HAL-Remoting). Da der Client getService auf einem IFoo-Objekt aus Version 1.0 des Pakets, hwservicemanager gibt nur dann eine Serverimplementierung zurück, wenn diese -Implementierung ist mit 1.0-Clients kompatibel. In der Praxis bedeutet das bedeutet nur Serverimplementierungen mit Version 1.n (Version x.(y+1) einer Schnittstelle muss erweitert werden (übernehmen von) x.y.

Außerdem wird die Methode castFrom zum Umwandeln zwischen verschiedenen Benutzeroberflächen. Bei dieser Methode wird ein IPC-Aufruf an die Remote- um sicherzustellen, dass der zugrunde liegende Typ angefordert. Wenn der angeforderte Typ nicht verfügbar ist, gilt: nullptr zurückgegeben.

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

Asynchrone Callbacks

Viele bestehende HAL-Implementierungen kommunizieren mit asynchroner Hardware, was bedeutet, Sie benötigen eine asynchrone Methode, um Kunden über neue Ereignisse zu informieren, aufgetreten. Eine HIDL-Schnittstelle kann als asynchroner Rückruf verwendet werden, da HIDL -Schnittstellenfunktionen können HIDL-Schnittstellenobjekte als Parameter verwenden.

Beispieldatei IFooCallback.hal:

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

Beispiel für eine neue Methode in IFoo, die eine IFooCallback-Parameter:

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);
};

Der Client, der die IFoo-Schnittstelle verwendet, ist der server der IFooCallback-Schnittstelle bietet es eine Implementierung von 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
    }
};

Er kann diese auch einfach an eine vorhandene Instanz des IFoo-Schnittstelle:

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

Der Server, der IFoo implementiert, empfängt dies als sp<IFooCallback>-Objekt. Er kann den Callback speichern wenn er diese Schnittstelle verwenden möchte.

Todesopfer

Da Dienstimplementierungen in einem anderen Prozess ausgeführt werden können, dass der Prozess zur Implementierung einer Schnittstelle beendet wird, während der Client aktiv bleibt. Alle Aufrufe eines Interface-Objekts, das in einem abgebrochenen Prozess gehostet wird, schlagen fehl mit einem Transportfehler (isOK() gibt false zurück). Die einzige Möglichkeit, Wiederherstellung nach einem solchen Fehler ist die Anforderung einer neuen Instanz des Dienstes, I<InterfaceName>::getService() wird angerufen. Dies funktioniert nur, wenn Der abgestürzte Prozess wurde neu gestartet und seine Dienste wurden neu registriert servicemanager (gilt generell für HAL-Implementierungen).

Anstatt reaktiv damit zu arbeiten, können Benutzeroberflächen-Clients auch Registrieren Sie einen Empfänger der Todesfälle, um über die Beendigung eines Dienstes benachrichtigt zu werden. Um sich für solche Benachrichtigungen auf einer abgerufenen IFoo-Oberfläche zu registrieren, kann er Folgendes tun:

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

Der recipient-Parameter muss eine Implementierung der android::hardware::hidl_death_recipient-Schnittstelle von HIDL bereitgestellt, mit einer einzigen serviceDied()-Methode, die aus einem Thread im RPC-Threadpool, wenn der Prozess, der die Schnittstelle hostet, beendet wird:

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
    }
}

Der Parameter cookie enthält das Cookie, das mit übergeben wurde: linkToDeath(), während der who-Parameter ein Schwachstellenzeiger auf das Objekt, das den Dienst im Client darstellt. Mit der oben angegebener Beispielaufruf; cookie ist 1.481 und who gleich foo.

Es ist auch möglich, einen Empfänger, der verstorben ist, nach der Registrierung abzumelden:

foo->unlinkToDeath(recipient);