Services et transfert de données

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 des 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:

  1. Créer une sous-classe de la classe/interface HIDL hidl_death_recipient (en C++ et non en HIDL).
  2. Remplacez sa méthode serviceDied().
  3. Instanciez un objet de la sous-classe hidl_death_recipient.
  4. Appelez la méthode linkToDeath() sur le service à surveiller. en transmettant l'objet d'interface de IDeathRecipient. 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 ou MQDescriptorUnsync. 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.
    Aucun de ces types n'est autorisé à subir un dépassement de capacité (échec de la lecture à partir d'une file d'attente vide) et chaque type ne peut avoir qu'un seul auteur.

Pour en savoir plus sur FMQ, consultez File d'attente de messages rapide (FMQ).