HIDL

Le langage de définition d'interface HAL ou HIDL (prononcé "hide-l") est un langage de description d'interface (IDL) pour spécifier l'interface entre un HAL et ses utilisateurs. Il permet de spécifier des types et des appels de méthode, regroupés dans des interfaces et des packages. Plus largement, HIDL est un système de communication entre des bases de code qui peuvent être compilées indépendamment. Depuis Android 10, HIDL est obsolète et Android migre pour utiliser AIDL partout.

HIDL est destiné à être utilisé pour la communication inter-processus (IPC). La communication entre les processus est appelé Binderized . Pour les bibliothèques qui doivent être liées à un processus, un mode passthrough est également disponible (non pris en charge en Java).

HIDL spécifie des structures de données et des signatures de méthodes, organisées en interfaces (semblables à une classe) qui sont collectées dans des packages. La syntaxe de HIDL semblera familière aux programmeurs C++ et Java, bien qu'avec un ensemble différent de mots-clés. HIDL utilise également des annotations de style Java.

Conception HIDL

L'objectif de HIDL est que le framework puisse être remplacé sans avoir à reconstruire les HAL. HALs seront construits par les vendeurs ou les fabricants de SOC et mis dans un /vendor partition sur le périphérique, ce qui permet le cadre, dans sa propre partition, être remplacé par un OTA sans recompiler les HALs.

La conception HIDL équilibre les préoccupations suivantes :

  • L' interopérabilité. Créez des interfaces interopérables de manière fiable entre les processus qui peuvent être compilés avec diverses architectures, chaînes d'outils et configurations de construction. Les interfaces HIDL sont versionnées et ne peuvent pas être modifiées après leur publication.
  • Efficacité. HIDL essaie de minimiser le nombre d'opérations de copie. Les données définies par HIDL sont livrées au code C++ dans des structures de données de mise en page standard C++ qui peuvent être utilisées sans décompresser. HIDL fournit également des interfaces de mémoire partagée et, comme les RPC sont par nature quelque peu lents, HIDL prend en charge deux manières de transférer des données sans utiliser un appel RPC : la mémoire partagée et une file d'attente de messages rapide (FMQ).
  • Intuitive. HIDL évite épineux problèmes de propriété de la mémoire en utilisant uniquement in les paramètres pour RPC (voir Android Interface Definition Language (AIDL) ); les valeurs qui ne peuvent pas être renvoyées efficacement à partir des méthodes sont renvoyées via des fonctions de rappel. Ni le passage de données dans HIDL pour le transfert ni la réception de données de HIDL ne changent la propriété des données - la propriété reste toujours avec la fonction appelante. Les données ne doivent persister que pendant la durée de la fonction appelée et peuvent être détruites immédiatement après le retour de la fonction appelée.

Utilisation du mode passthrough

Pour mettre à jour les appareils exécutant des versions antérieures d'Android vers Android O, vous pouvez encapsuler les HAL classiques (et hérités) dans une nouvelle interface HIDL qui sert la HAL en modes binderized et même processus (passthrough). Ce wrapping est transparent à la fois pour HAL et pour le framework Android.

Le mode passthrough est disponible uniquement pour les clients et les implémentations C++. Les appareils exécutant des versions antérieures d'Android n'ont pas de HAL écrits en Java, les HAL Java sont donc intrinsèquement liées.

Quand un .hal fichier est compilé, hidl-gen produit un fichier d' en- tête supplémentaire intercommunication BsFoo.h en plus des en- têtes utilisés pour la communication de liant; Cela définit d' en- tête fonctions à dlopen ed. Comme les HAL passthrough s'exécutent dans le même processus dans lequel elles sont appelées, dans la plupart des cas, les méthodes passthrough sont invoquées par un appel de fonction direct (même thread). oneway méthodes fonctionnent dans leur propre fil car ils ne sont pas destinés à attendre la couche d' abstraction pour les traiter (ce qui signifie une HAL que les utilisations oneway méthodes en mode passthrough doivent être thread-safe).

Compte tenu d' une IFoo.hal , BsFoo.h enveloppe les méthodes HIDL généré pour fournir des fonctionnalités supplémentaires (telles que la réalisation oneway transactions gérées dans un autre thread). Ce fichier est similaire à BpFoo.h , mais au lieu de passer des appels IPC en utilisant un liant, les fonctions souhaitées sont directement invoquées. Mises en œuvre futures de HALs peuvent fournir de multiples implémentations, comme FooFast HAL et HAL FooAccurate. Dans de tels cas, un dossier pour chaque application supplémentaire serait créé (par exemple, PTFooFast.cpp et PTFooAccurate.cpp ).

Reliure des HAL passthrough

Vous pouvez lier les implémentations HAL qui prennent en charge le mode passthrough. Étant donné une HAL Interface abcd@MN::IFoo , deux paquets sont créés:

  • abcd@MN::IFoo-impl . Contient la mise en œuvre de la couche d' abstraction et fonction expose IFoo* HIDL_FETCH_IFoo(const char* name) . Sur les périphériques existants, ce paquet est dlopen ed et la mise en œuvre est instancié à l' aide HIDL_FETCH_IFoo . Vous pouvez générer le code de base en utilisant hidl-gen et -Lc++-impl et -Landroidbp-impl .
  • abcd@MN::IFoo-service . Ouvre le HAL passthrough et s'enregistre en tant que service binderisé, permettant à la même implémentation HAL d'être utilisée à la fois comme passthrough et binderized.

Compte tenu du type IFoo , vous pouvez appeler sp<IFoo> IFoo::getService(string name, bool getStub) pour avoir accès à une instance de IFoo . Si getStub est vrai, getService tente d'ouvrir le HAL uniquement en mode passthrough. Si getStub est faux, getService tente de trouver un service binderized; si cela échoue, il essaie alors de trouver le service de relais. Le getStub paramètre ne doit jamais être utilisé , sauf dans defaultPassthroughServiceImplementation . (Les appareils lancés avec Android O sont des appareils entièrement liés, donc l'ouverture d'un service en mode passthrough est interdite.)

Grammaire HIDL

De par sa conception, le langage HIDL est similaire au C (mais n'utilise pas le préprocesseur C). Tous les signes de ponctuation pas décrit ci - dessous ( en dehors de l'utilisation évidente de = et | ) fait partie de la grammaire.

Note: Pour plus de détails sur le style de code HIDL, consultez le code Style Guide .

  • /** */ indique un commentaire de documentation. Ceux-ci peuvent être appliqués uniquement aux déclarations de type, de méthode, de champ et de valeur enum.
  • /* */ Indique un commentaire multiligne.
  • // indique un commentaire à la fin de la ligne. Mis à part // , les nouvelles lignes sont les mêmes que les autres espaces.
  • Dans la grammaire exemple ci - dessous, le texte de // à la fin de la ligne ne fait pas partie de la grammaire , mais est plutôt un commentaire sur la grammaire.
  • [empty] signifie que le terme peut être vide.
  • ? suivre un littéral ou un terme signifie qu'il est facultatif.
  • ... indique séquence contenant zéro ou plusieurs éléments de séparation avec des signes de ponctuation comme indiqué. Il n'y a pas d'arguments variadiques dans HIDL.
  • Des virgules séparent les éléments de séquence.
  • Les points-virgules terminent chaque élément, y compris le dernier élément.
  • MAJUSCULES est un non-terminal.
  • italics est une famille de jeton comme integer ou identifier (règles d'analyse standard C).
  • constexpr est un style de C expression constante (telle que 1 + 1 et 1L << 3 ).
  • import_name est un nom de paquet ou d'une interface, qualifiée comme décrit dans HIDL Versioning .
  • Minuscules words sont des jetons littérales.

Exemple:

ROOT =
    PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... }  // not for types.hal
  | PACKAGE IMPORTS ITEM ITEM...  // only for types.hal; no method definitions

ITEM =
    ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?;
  |  safe_union identifier { UFIELD; UFIELD; ...};
  |  struct identifier { SFIELD; SFIELD; ...};  // Note - no forward declarations
  |  union identifier { UFIELD; UFIELD; ...};
  |  enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar
  |  typedef TYPE identifier;

VERSION = integer.integer;

PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION;

PREAMBLE = interface identifier EXTENDS

EXTENDS = <empty> | extends import_name  // must be interface, not package

GENERATES = generates (FIELD, FIELD ...)

// allows the Binder interface to be used as a type
// (similar to typedef'ing the final identifier)
IMPORTS =
   [empty]
  |  IMPORTS import import_name;

TYPE =
  uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t |
 float | double | bool | string
|  identifier  // must be defined as a typedef, struct, union, enum or import
               // including those defined later in the file
|  memory
|  pointer
|  vec<TYPE>
|  bitfield<TYPE>  // TYPE is user-defined enum
|  fmq_sync<TYPE>
|  fmq_unsync<TYPE>
|  TYPE[SIZE]

FIELD =
   TYPE identifier

UFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...};
  |  struct identifier { FIELD; FIELD; ...};
  |  union identifier { FIELD; FIELD; ...};
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SIZE =  // Must be greater than zero
     constexpr

ANNOTATIONS =
     [empty]
  |  ANNOTATIONS ANNOTATION

ANNOTATION =
  |  @identifier
  |  @identifier(VALUE)
  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)

ANNO_ENTRY =
     identifier=VALUE

VALUE =
     "any text including \" and other escapes"
  |  constexpr
  |  {VALUE, VALUE ...}  // only in annotations

ENUM_ENTRY =
     identifier
  |  identifier = constexpr

Terminologie

Cette section utilise les termes suivants liés à HIDL :

reliure Indique que HIDL est utilisé pour les appels de procédure à distance entre les processus, implémentés via un mécanisme de type Binder. Voir aussi passthrough.
rappel, asynchrone Interface servie par un utilisateur HAL, passée à HAL (via une méthode HIDL), et appelée par HAL pour retourner des données à tout moment.
rappel, synchrone Renvoie les données de l'implémentation de la méthode HIDL d'un serveur au client. Inutilisé pour les méthodes qui renvoient void ou une valeur primitive unique.
client Processus qui appelle les méthodes d'une interface particulière. Un processus HAL ou framework peut être client d'une interface et serveur d'une autre. Voir aussi passthrough.
s'étend Indique une interface qui ajoute des méthodes et/ou des types à une autre interface. Une interface ne peut étendre qu'une seule autre interface. Peut être utilisé pour un incrément de version mineur dans le même nom de package ou pour un nouveau package (par exemple, une extension de fournisseur) pour s'appuyer sur un package plus ancien.
génère Indique une méthode d'interface qui renvoie des valeurs au client. Pour renvoyer une valeur non primitive ou plusieurs valeurs, une fonction de rappel synchrone est générée.
interface Collection de méthodes et de types. Traduit en classe en C++ ou Java. Toutes les méthodes d'une interface sont appelées dans le même sens : un processus client appelle des méthodes implémentées par un processus serveur.
une manière Lorsqu'il est appliqué à une méthode HIDL, indique que la méthode ne renvoie aucune valeur et ne bloque pas.
emballer Collection d'interfaces et de types de données partageant une version.
traverser Mode de HIDL dans lequel le serveur est une bibliothèque partagée, dlopen ed par le client. En mode passthrough, le client et le serveur sont le même processus mais des bases de code distinctes. Utilisé uniquement pour intégrer les bases de code héritées dans le modèle HIDL. Voir aussi Binderized.
serveur Processus qui implémente les méthodes d'une interface. Voir aussi passthrough.
transport Infrastructure HIDL qui déplace les données entre le serveur et le client.
version Version d'un paquet. Se compose de deux nombres entiers, majeur et mineur. Des incréments de version mineurs peuvent ajouter (mais pas modifier) ​​des types et des méthodes.