Cette page explique comment enregistrer et découvrir des services et comment envoyer
des données à un service en appelant les méthodes définies dans les interfaces dans .hal
.
Enregistrer les services
Les serveurs d'interface HIDL (objets mettant en œuvre l'interface) peuvent être enregistrés en tant que services nommés. Le nom enregistré n'a pas besoin d'être associé à l'interface ou nom du package. Si aucun nom n'est spécifié, le nom "default" est utilisée. cela devrait être utilisé pour les HAL qui n'ont pas besoin d'enregistrer deux implémentations de la même de commande. Par exemple, l'appel C++ d'enregistrement de service défini dans chaque est la suivante:
status_t status = myFoo->registerAsService(); status_t anotherStatus = anotherFoo->registerAsService("another_foo_service"); // if needed
La version d'une interface HIDL est incluse dans l'interface elle-même. Il est
automatiquement associé à l'enregistrement du service et peuvent être récupérés via un
appel de méthode (android::hardware::IInterface::getInterfaceVersion()
)
sur chaque interface HIDL. Les objets serveur n'ont pas besoin d'être enregistrés et peuvent être transmis
via les paramètres de méthode HIDL vers un autre processus qui effectue des appels de méthode HIDL
sur le serveur.
Découvrir les services
Les requêtes par code client sont effectuées pour une interface donnée, par nom et par
en appelant getService
sur la classe HAL souhaitée:
// C++ sp<V1_1::IFooService> service = V1_1::IFooService::getService(); sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service"); // Java V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */); V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);
Chaque version d'une interface HIDL est traitée comme une interface distincte. Ainsi,
IFooService
version 1.1 et IFooService
version 2.2
peuvent tous deux être enregistrés en tant que "foo_service" et
getService("foo_service")
sur l'une ou l'autre des interfaces permet d'obtenir
pour cette interface. C'est pourquoi, dans la plupart des cas, aucun paramètre de nom n'a besoin
à fournir à des fins d'enregistrement ou de découverte (nom "par défaut").
L'objet d'interface fournisseur joue également un rôle dans le mode de transport du
renvoyée. Pour une interface IFoo
dans un package
android.hardware.foo@1.0
, l'interface renvoyée par
IFoo::getService
utilise toujours la méthode de transport déclarée pour
android.hardware.foo
dans le fichier manifeste de l'appareil si l'entrée existe ;
et si la méthode de transport n'est pas disponible, la valeur nullptr est renvoyée.
Dans certains cas, il peut être nécessaire de continuer immédiatement, même sans
obtenir le service. Cela peut se produire (par exemple) lorsqu'un client souhaite
gérer les notifications des services proprement dits ou celles d'un programme de diagnostic (par exemple,
atrace
), qui doit obtenir tous les services matériels et les récupérer. Dans
dans ce cas, des API supplémentaires sont fournies, telles que tryGetService
en C++ ou
getService("instance-name", false)
en Java. L'ancienne API
getService
fourni en Java doit également être utilisé avec le service
les notifications. L'utilisation de cette API n'évite pas la condition de concurrence dans laquelle un serveur
s'enregistre une fois que le client l'a demandée avec l'une de ces API no-retry.
Notifications d'arrêt du service
Clients qui souhaitent être avertis en cas de décès d'un service des notifications fournies par le framework. Pour recevoir des notifications, le client doit:
- Créer une sous-classe de la classe/interface HIDL
hidl_death_recipient
(en C++ et non en HIDL). - Remplacez sa méthode
serviceDied()
. - Instanciez un objet de la sous-classe
hidl_death_recipient
. - Appelez la méthode
linkToDeath()
sur le service à surveiller. en transmettant l'objet d'interface deIDeathRecipient
. Notez que cette ne prend pas possession du destinataire du décès ni du proxy est appelé.
Exemple de pseudo-code (C++ et Java sont similaires):
class IMyDeathReceiver : hidl_death_recipient { virtual void serviceDied(uint64_t cookie, wp<IBase>& service) override { log("RIP service %d!", cookie); // Cookie should be 42 } }; .... IMyDeathReceiver deathReceiver = new IMyDeathReceiver(); m_importantService->linkToDeath(deathReceiver, 42);
Un même destinataire peut être enregistré dans plusieurs services différents.
Transfert des données
Des données peuvent être envoyées à un service en appelant les méthodes définies dans les interfaces dans
.hal
fichiers. Il existe deux types de méthodes:
- Les méthodes de blocage attendent que le serveur génère une résultat.
- Les méthodes Oneway n'envoient les données que dans une seule direction et n'envoient pas . Si la quantité de données en cours de transfert dans les appels RPC dépasse l'implémentation limites, les appels peuvent soit bloquer ou renvoyer une indication d'erreur (comportement pas encore déterminé).
Une méthode qui ne renvoie pas de valeur, mais qui n'est pas déclarée en tant que
oneway
est toujours bloquant.
Toutes les méthodes déclarées dans une interface HIDL sont appelées dans une seule direction, à partir du HAL ou dans celui-ci. L'interface ne spécifie pas la direction dans laquelle il est appelé. Les architectures qui ont besoin d'appels provenant de le HAL doit fournir deux interfaces (ou plus) dans le package HAL et diffuser le l'interface appropriée de chaque processus. Les mots client et server sont utilisés en fonction du sens d'appel de l'interface (autrement dit, le HAL peut être un serveur d'une interface et un client d'une autre .
Rappels
Le terme rappel fait référence à deux concepts différents, distingués par rappel synchrone et rappel asynchrone.
Les rappels synchrones sont utilisés dans certaines méthodes HIDL qui renvoient données. Une méthode HIDL qui renvoie plusieurs valeurs (ou renvoie une valeur de type non primitif) renvoie ses résultats via une fonction de rappel. S'il n'en existe qu'un est renvoyée et il s'agit d'un type primitif, aucun rappel n'est utilisé et est renvoyée par la méthode. Le serveur implémente les méthodes HIDL et le client implémente les rappels.
Les rappels asynchrones permettent au serveur d'une interface HIDL de
les appels de départ. Cela se fait en transmettant une instance d'une deuxième interface
via la première interface. Le client de la première interface doit agir en tant que
serveur du second. Le serveur de la première interface peut appeler des méthodes sur la
deuxième objet d'interface. Par exemple, une implémentation HAL peut envoyer des informations
de manière asynchrone au processus qui l'utilise en appelant des méthodes sur un
d'interface créé et diffusé par ce processus. Méthodes des interfaces utilisées
pour le rappel asynchrone peut être bloquant (et peut renvoyer des valeurs à l'appelant)
ou oneway
. Pour obtenir un exemple, consultez la section "Rappels asynchrones". dans
HIDL C++
Pour simplifier la propriété de la mémoire, les appels de méthode et les rappels ne prennent
Paramètres in
et ne sont pas compatibles avec out
ni
Paramètres inout
.
Limites par transaction
Les limites par transaction ne sont pas imposées à la quantité de données envoyées en HIDL
de méthodes et de rappels. Toutefois, les appels de plus de 4 Ko par transaction sont
considéré comme excessif. Si cela se produit, modifier l'architecture de l'interface HIDL donnée
est recommandé. Une autre limite est la quantité
de ressources disponibles pour le HIDL
pour gérer plusieurs transactions simultanées. Multiples
les transactions peuvent être en cours simultanément en raison de plusieurs threads ou
processus envoyant des appels à un processus ou à plusieurs appels oneway
qui
ne sont pas gérés rapidement
par le processus de réception. L'espace total maximal
disponible pour toutes les transactions simultanées est de 1 Mo par défaut.
Dans une interface bien conçue, dépasser ces limites de ressources se produire ; Si c'est le cas, l'appel qui les a dépassé peut être bloqué jusqu'à des ressources deviennent disponibles ou signalent une erreur de transport. Chaque occurrence de au-delà des limites par transaction ou au dépassement des ressources d'implémentation HIDL l'agrégation des transactions en cours est consignée pour faciliter le débogage.
Implémentations de méthodes
HIDL génère des fichiers d'en-tête déclarant les types, les méthodes et dans le langage cible (C++ ou Java). Le prototype du modèle de définition HIDL et les rappels sont les mêmes pour le code client et le code serveur. The HIDL fournit des implémentations proxy des méthodes sur le côté appelant, qui organisent les données pour le transport IPC, et bouchon du côté appelé qui transmet les données aux implémentations de développement les méthodes.
L'appelant d'une fonction (méthode ou rappel HIDL) est propriétaire des données. les structures transmises dans la fonction et en conserve la propriété après l'appel ; dans dans tous les cas, l'appelé n'a pas besoin de libérer de l'espace de stockage.
- En C++, les données peuvent être en lecture seule (les tentatives d'écriture peuvent entraîner (erreur de segmentation) et sont valides pendant toute la durée de l'appel. Le client peut copier les données en profondeur pour les propager au-delà de l'appel.
- En Java, le code reçoit une copie locale des données (un objet Java normal), qu'il peut conserver et modifier, ou autoriser la récupération de mémoire.
Transfert de données non-RPC
HIDL propose deux méthodes pour transférer des données sans utiliser d'appel RPC: partagé et une file d'attente rapide de messages (FMQ), tous deux pris en charge uniquement en C++.
- Mémoire partagée : Type HIDL intégré
memory
est utilisé pour transmettre un objet représentant la mémoire partagée qui a été allouée. Peut être utilisée dans un processus de réception pour mapper la mémoire partagée. - File d'attente de messages rapide (FMQ). HIDL fournit un message modélisé
type de file d'attente qui implémente la transmission de messages sans attente. Il n'utilise pas le noyau
ou du planificateur en mode passthrough ou lié (la communication inter-appareil
ne possèdent pas ces propriétés). En général, le HAL définit sa fin
de la file d'attente,
créer un objet pouvant être transmis via RPC via un paramètre de l'API
Type HIDL
MQDescriptorSync
ouMQDescriptorUnsync
. Ce peut être utilisé par le processus de réception pour configurer l'autre extrémité de la file d'attente.- Les files d'attente de synchronisation ne sont pas autorisées à déborder et ne peuvent en posséder qu'une en lecture seule.
- Les files d'attente non synchronisées peuvent déborder et peuvent avoir de nombreux lecteurs, chacun doit lire des données à temps ou les perdre.
Pour en savoir plus sur FMQ, consultez File d'attente de messages rapide (FMQ).