HIDL

Le langage de définition d'interface HAL, ou HIDL, est un langage de description d'interface (IDL) permettant de spécifier l'interface entre un HAL et de ses utilisateurs. HIDL permet de spécifier des types et des appels de méthode, collectés dans interfaces et packages. Plus généralement, HIDL est un système de communication entre codebases pouvant être compilés indépendamment.

Le protocole HIDL est destiné à la communication inter-processus (IPC). Les HAL créées en HDL sont appelées HAL liées, car elles peuvent communiquer avec d'autres couches d'architecture à l'aide de la liaison appels de communication inter-processus (IPC, inter-process communication). Les HAL avec liaison s'exécutent dans un processus distinct de celui du client. qui les utilise. Pour doivent être liées à un processus, un passthrough est également disponible (non compatible avec Java).

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

Terminologie

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

lié Indique que HIDL est utilisé pour les appels de procédure à distance entre les processus. implémentée via un mécanisme de type Binder. Voir aussi passthrough.
rappel, asynchrone Interface diffusée par un utilisateur HAL, transmise au HAL (à l'aide d'une méthode HIDL) appelé par le HAL pour renvoyer des données à tout moment.
rappel, synchrone Renvoie au client les données issues de l'implémentation de la méthode HIDL d'un serveur. Cet attribut n'est pas utilisé pour les méthodes qui renvoient une valeur nulle ou une seule valeur primitive.
client Processus qui appelle les méthodes d'une interface particulière. Un framework HAL ou Android processus peut être un client d'une interface et un serveur d'une autre. Voir aussi passthrough.
é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 mineur incrément de version dans le même nom de package ou pour un nouveau package (par exemple, un fournisseur ) pour exploiter un package plus ancien.
génère Indique une méthode d'interface qui renvoie des valeurs au client. Pour retourner une valeur non primitive ou plusieurs valeurs, une fonction de rappel synchrone est généré.
interface Collection de méthodes et de types. Traduit en une classe C++ ou Java. Tout méthodes dans une interface sont appelés dans la même direction: un processus client invoque des méthodes implémentées par un processus serveur.
aller simple Lorsqu'elle est appliquée à une méthode HIDL, indique que la méthode ne renvoie aucune valeur et ne bloque pas.
colis Collection d'interfaces et de types de données partageant une version.
passthrough Mode HIDL dans lequel le serveur est une bibliothèque partagée, dlopen par le client. En mode passthrough, le client et le serveur sont le même processus, mais des codebases distincts. Utilisé uniquement pour intégrer d'anciens codebases dans le modèle HIDL. Voir aussi la section 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 package. Il se compose de deux entiers, majeur et mineur. Mineur les incréments de version peuvent ajouter (mais pas modifier) des types et des méthodes.

Conception HIDL

L'objectif de HIDL est que le framework Android peut être remplacé sans avoir à reconstruire les HAL. Les HAL sont conçus par des fournisseurs ou des fabricants de SOC et intégrés /vendor sur l'appareil, ce qui permet d'activer le framework Android lui-même. partition, à remplacer par une OTA sans recompiler les HAL.

La conception HIDL permet de contrebalancer les problèmes suivants:

  • Interopérabilité. Créer des interfaces interopérables de manière fiable entre les processus, qui peuvent être compilés avec différentes architectures, chaînes d'outils et des configurations de compilation. Les interfaces HIDL sont gérées par version et ne peuvent pas être modifiées. après leur publication.
  • Efficacité. HIDL tente de minimiser le nombre de copies operations. Les données définies par HIDL sont transmises au code C++ avec une mise en page standard C++ des structures de données qui peuvent être utilisées sans désimbriquer. HIDL fournit également des interfaces mémoire et, comme les RPC sont intrinsèquement lents, HIDL prend en charge deux méthodes de transfert de données sans appel RPC: la mémoire partagée et l'accès rapide File d'attente des messages (FMQ)
  • Intuitif. HIDL évite les problèmes épineux de propriété de mémoire en en n'utilisant que des paramètres in pour RPC (consultez Sur Android langage de définition d'interface (AIDL) des valeurs qui ne peuvent pas être efficaces renvoyés par les méthodes sont renvoyés via des fonctions de rappel. Sans données dans HIDL pour le transfert ou la réception de données de HIDL, change la propriété du données : la propriété reste toujours associée à la fonction appelante. Les données doivent ne persistent que pendant la durée de la fonction appelée et peuvent être détruits immédiatement après le retour de la fonction appelée.

Utiliser le mode passthrough

Pour mettre à jour les appareils équipés de versions antérieures d'Android vers Android O, vous pouvez : d'encapsuler les HAL classiques (et anciens) dans une nouvelle interface HIDL qui diffuse le HAL en mode lié et en mode même processus (passthrough). Cette encapsulation transparente pour le HAL et le framework Android.

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

Lorsqu'un fichier .hal est compilé, hidl-gen génère une Fichier d'en-tête passthrough supplémentaire BsFoo.h en plus des en-têtes utilisé pour la communication de liaison ; cet en-tête définit les fonctions dlopen éd. Comme les HAL passthrough s'exécutent dans le même processus que dans la plupart des cas, les méthodes passthrough sont invoquées (même thread). Les méthodes oneway s'exécutent dans leur propre thread car ils ne sont pas destinés à attendre que le HAL les traite (cela signifie que qui utilise des méthodes oneway en mode passthrough doit être thread-safe).

Avec un IFoo.hal, BsFoo.h encapsule le code HIDL généré pour fournir des fonctionnalités supplémentaires (comme oneway transactions exécutées dans un autre thread). Ce fichier est similaire à BpFoo.h. Toutefois, au lieu de transmettre les appels IPC à l'aide du binder, le les fonctions souhaitées sont directement appelées. Implémentations futures des HAL peut fournir plusieurs implémentations, comme FooFast HAL et un service HAL avec FooPrécision. Dans ce cas, un fichier pour chaque implémentation supplémentaire (par exemple, PTFooFast.cpp et PTFooAccurate.cpp).

Binderging Passthrough HAL (HAL)

Vous pouvez associer des implémentations HAL compatibles avec le mode passthrough. Avec un Interface HAL a.b.c.d@M.N::IFoo, deux packages sont créés:

  • a.b.c.d@M.N::IFoo-impl Contient l'implémentation de la couche HAL et expose la fonction IFoo* HIDL_FETCH_IFoo(const char* name). Activé sur d'anciens appareils, ce package est dlopendisponible et l'implémentation instanciée à l'aide de HIDL_FETCH_IFoo. Vous pouvez générer le code de base avec hidl-gen et -Lc++-impl, et -Landroidbp-impl
  • a.b.c.d@M.N::IFoo-service Ouvre le HAL du passthrough et s'enregistre en tant que service lié, permettant ainsi la même implémentation HAL à utiliser à la fois en tant que passthrough et en tant que liaison.

Compte tenu du type IFoo, vous pouvez appeler sp<IFoo> IFoo::getService(string name, bool getStub) pour accéder à une instance sur IFoo. Si getStub est "true", getService tente d'ouvrir le HAL uniquement en mode passthrough. Si getStub correspond à "false", getService tente de trouver un service lié. si échoue, il tente ensuite de trouver le service passthrough. getStub ne doit jamais être utilisé, sauf dans defaultPassthroughServiceImplementation (Appareils dont le lancement est Les appareils Android O sont entièrement liés. Par conséquent, ouvrir un service en mode passthrough n'est pas autorisé.)

Grammaire HIDL

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

Remarque:Pour en savoir plus sur le style de code HIDL, consultez les Guide de style du code.

  • /** */ indique un commentaire sur la documentation. Ceux-ci peuvent être appliqués uniquement pour les déclarations de type, de méthode, de champ et de valeur d'énumération.
  • /* */ indique un commentaire multiligne.
  • // indique un commentaire en fin de ligne. En dehors de //, les sauts de ligne sont identiques à tous les autres espaces blancs.
  • Dans l'exemple de grammaire ci-dessous, le texte compris entre // et la fin du ne fait pas partie de la grammaire, mais est un commentaire sur cette dernière.
  • [empty] signifie que le terme peut être vide.
  • ? après un littéral ou un terme signifie qu'il est facultatif.
  • ... indique une séquence contenant zéro ou plusieurs éléments avec qui sépare la ponctuation, comme indiqué. Il n'y a pas d'arguments variables en HIDL.
  • Les éléments de séquence sont séparés par des virgules.
  • Un point-virgule termine chaque élément, y compris le dernier.
  • MAJUSCULES est un élément non final.
  • italics est une famille de jetons telle que integer ou identifier (standard C) règles d'analyse).
  • constexpr est une expression constante de style C (par exemple, 1 + 1 et 1L << 3).
  • import_name est un nom de package ou d'interface, qualifié comme décrit dans la section HIDL Gestion des versions
  • Les words minuscules sont des jetons littéraux.

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