Chaque interface définie dans un package HIDL a sa propre classe C++ générée automatiquement dans l'espace de noms de son package. Les clients et les serveurs gèrent les interfaces dans différentes manières:
- Les serveurs implémentent les interfaces.
- Les clients appellent des méthodes au niveau des interfaces.
Les interfaces peuvent être enregistrées à l'aide de leur nom par le serveur ou transmises en tant que aux méthodes définies par HIDL. Par exemple, le code du framework peut diffuser pour recevoir des messages asynchrones du HAL et transmettre cette interface directement au HAL sans l'enregistrer.
Implémentation du serveur
Un serveur qui implémente l'interface IFoo
doit inclure l'élément
Fichier d'en-tête IFoo
généré automatiquement:
#include <android/hardware/samples/1.0/IFoo.h>
L'en-tête est automatiquement exporté par la bibliothèque partagée du
Interface IFoo
à associer. Exemple IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
Exemple de squelette pour une implémentation serveur de l'interface 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(); } ... };
Pour rendre l'implémentation d'une interface de serveur disponible pour un client, vous permet:
- Enregistrez l'implémentation de l'interface à l'aide de la commande
hwservicemanager
(voir détails ci-dessous),
OU
- Transmettez l'implémentation de l'interface en tant qu'argument d'une d'interface unique (pour les données, consultez la section Asynchrone ).
Lors de l'enregistrement de l'implémentation de l'interface,
Le processus hwservicemanager
assure le suivi des interfaces HIDL enregistrées
en cours d'exécution sur l'appareil
par nom et par version. Les serveurs peuvent enregistrer une interface HIDL
l'implémentation par nom et les clients peuvent demander des implémentations de service par nom
et sa version. Ce processus sert l'interface HIDL
android.hidl.manager@1.0::IServiceManager
Chaque fichier d'en-tête d'interface HIDL généré automatiquement (tel que IFoo.h
)
comporte une méthode registerAsService()
qui peut être utilisée pour enregistrer le
l'implémentation de l'interface avec hwservicemanager
. La seule
L'argument requis est le nom des implémentations d'interface en tant que clients
utilisez ce nom pour récupérer l'interface à partir de hwservicemanager
.
plus tard:
::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
traite la combinaison de
[package@version::interface, instance_name]
comme unique à activer
différentes interfaces (ou différentes versions de la même interface) à enregistrer
avec des noms d'instances identiques sans conflit. Si vous appelez
registerAsService()
avec exactement la même version de package, l'interface
et le nom de l'instance, hwservicemanager
supprime sa référence au
précédemment enregistré et utilise le nouveau.
Implémentation client
Tout comme le serveur, un client doit #include
à chaque interface
elle fait référence à:
#include <android/hardware/samples/1.0/IFoo.h>
Un client peut obtenir une interface de deux manières:
- Via
I<InterfaceName>::getService
(via lehwservicemanager
). - Via une méthode d'interface
Chaque fichier d'en-tête d'interface généré automatiquement possède un getService
statique
permettant de récupérer une instance de service
hwservicemanager
:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
Le client dispose maintenant d'une interface IFoo
et peut appeler des méthodes pour
comme s'il s'agissait d'une implémentation de classe locale. En réalité, l'implémentation
peuvent s'exécuter dans le même processus, dans un processus différent, voire sur un autre appareil
(avec communication à distance HAL). Comme le client a appelé getService
sur un
Objet IFoo
inclus à partir de la version 1.0
du package,
hwservicemanager
ne renvoie une implémentation de serveur que si celle-ci
est compatible avec les clients 1.0
. En pratique,
signifie que seules les implémentations de serveur avec la version 1.n
(version
Le champ x.(y+1)
d'une interface doit être étendu (hériter de)
x.y
).
De plus, la méthode castFrom
est fournie pour caster entre
différentes interfaces. Cette méthode fonctionne en effectuant un appel d'IPC à la
pour s'assurer que le type sous-jacent est identique à celui utilisé
demandée. Si le type demandé n'est pas disponible, nullptr
est
renvoyé.
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
Rappels asynchrones
De nombreuses implémentations HAL existantes communiquent avec du matériel asynchrone, ce qui signifie elles ont besoin d'une méthode asynchrone pour informer les clients des nouveaux événements s'est produit. Une interface HIDL peut être utilisée comme rappel asynchrone, car HIDL les fonctions d'interface peuvent utiliser des objets d'interface HIDL comme paramètres.
Exemple de fichier d'interface IFooCallback.hal
:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
Exemple de nouvelle méthode dans IFoo
qui accepte une
Paramètre 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); };
Le client utilisant l'interface IFoo
est
server de l'interface IFooCallback
. elle fournit une
l'implémentation de 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 } };
Il peut également le transmettre à une instance existante du
Interface IFoo
:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
Le serveur qui implémente IFoo
le reçoit en tant que
sp<IFooCallback>
. Il peut stocker le rappel et appeler
au client chaque fois qu'il
veut utiliser cette interface.
Destinataires du décès
Comme les implémentations de services peuvent s'exécuter selon un processus différent, cela peut se produire
que le processus d'implémentation d'une interface
manque pendant que le client reste actif.
Tous les appels sur un objet d'interface hébergé dans un processus qui n'est plus actif échouent
avec une erreur de transport (isOK()
renvoie false
). Le seul moyen de
la récupération après un tel échec
consiste à demander une nouvelle instance du service
Appel de I<InterfaceName>::getService()
en cours. Cela ne fonctionne que si
le processus qui avait planté a redémarré et réenregistré ses services auprès du
servicemanager
(ce qui est généralement vrai pour les implémentations HAL).
Au lieu de traiter cela de façon réactive, les clients d'une interface peuvent également
enregistrer un destinataire du décès pour recevoir une notification lorsqu'un service cesse de fonctionner.
Pour recevoir de telles notifications sur une interface IFoo
récupérée, une
peut effectuer les opérations suivantes:
foo->linkToDeath(recipient, 1481 /* cookie */);
Le paramètre recipient
doit être une implémentation de
android::hardware::hidl_death_recipient
fournie par HIDL,
qui contient une seule méthode serviceDied()
appelée
à partir d'un thread du pool de threads RPC lorsque le processus hébergeant l'interface cesse de fonctionner:
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 } }
Le paramètre cookie
contient le cookie transmis avec
linkToDeath()
, alors que le paramètre who
contient
pointeur faible vers l'objet représentant
le service dans le client. Avec l'attribut
exemple d'appel fourni ci-dessus, cookie
est égal à 1481, et who
est égal à foo
.
Vous pouvez également annuler l'enregistrement d'un destinataire du décès après l'avoir enregistré:
foo->unlinkToDeath(recipient);