Le style de code HIDL ressemble au code C++ dans le framework Android, avec des retraits de quatre espaces et des noms de fichiers en majuscules et minuscules. Les déclarations de package, les importations et les docstrings sont similaires à ceux de Java, avec de légères modifications.
Les exemples suivants pour IFoo.hal
et types.hal
illustrent les styles de code HIDL et fournissent des liens rapides vers des informations sur chaque style (IFooClientCallback.hal
, IBar.hal
et IBaz.hal
ont été omis).
hardware/interfaces/foo/1.0/IFoo.hal |
---|
/* * (License Notice) */ package android.hardware.foo@1.0; import android.hardware.bar@1.0::IBar; import IBaz; import IFooClientCallback; /** * IFoo is an interface that… */ interface IFoo { /** * This is a multiline docstring. * * @return result 0 if successful, nonzero otherwise. */ foo() generates (FooStatus result); /** * Restart controller by power cycle. * * @param bar callback interface that… * @return result 0 if successful, nonzero otherwise. */ powerCycle(IBar bar) generates (FooStatus result); /** Single line docstring. */ baz(); /** * The bar function. * * @param clientCallback callback after function is called * @param baz related baz object * @param data input data blob */ bar(IFooClientCallback clientCallback, IBaz baz, FooData data); }; |
hardware/interfaces/foo/1.0/types.hal |
---|
/* * (License Notice) */ package android.hardware.foo@1.0; /** Replied status. */ enum Status : int32_t { OK, /* invalid arguments */ ERR_ARG, /* note, no transport related errors */ ERR_UNKNOWN = -1, }; struct ArgData { int32_t[20] someArray; vec<uint8_t> data; }; |
Conventions d'attribution de noms
Les noms de fonction, de variable et de fichier doivent être descriptifs. Évitez les abréviations excessives. Traitez les acronymes comme des mots (par exemple, utilisez INfc
au lieu de INFC
).
Structure des répertoires et dénomination des fichiers
La structure de répertoire doit se présenter comme suit:
ROOT-DIRECTORY
MODULE
SUBMODULE
(facultatif, peut comporter plusieurs niveaux)VERSION
Android.mk
IINTERFACE_1.hal
IINTERFACE_2.hal
…
IINTERFACE_N.hal
types.hal
(facultatif)
Où :
ROOT-DIRECTORY
peut correspondre à :hardware/interfaces
pour les packages HIDL de base.vendor/VENDOR/interfaces
pour les packages de fournisseurs, oùVENDOR
fait référence à un fournisseur de SoC ou à un OEM/ODM.
MODULE
doit être un mot minuscule qui décrit le sous-système (par exemple,nfc
). Si plusieurs mots sont nécessaires, utilisez desSUBMODULE
imbriqués. Il peut y avoir plusieurs niveaux d'imbrication.VERSION
doit être exactement la même version (major.minor) que celle décrite dans la section Versions.IINTERFACE_X
doit être le nom de l'interface avecUpperCamelCase
/PascalCase
(par exemple,INfc
), comme décrit dans la section Noms d'interface.
Exemple :
hardware/interfaces
nfc
1.0
Android.mk
INfc.hal
INfcClientCallback.hal
types.hal
Remarque:Tous les fichiers doivent disposer d'autorisations non exécutables (dans Git).
Noms des packages
Les noms de package doivent utiliser le format de nom complet (appelé PACKAGE-NAME
) suivant :
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
Où :
PACKAGE
est le package qui est mappé surROOT-DIRECTORY
. En particulier,PACKAGE
est :android.hardware
pour les packages HIDL principaux (mappage surhardware/interfaces
).vendor.VENDOR.hardware
pour les packages du fournisseur, oùVENDOR
fait référence à un fournisseur de SoC ou à un OEM/ODM (mappage survendor/VENDOR/interfaces
).
MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
sont exactement les mêmes noms de dossiers dans la structure décrite dans la section Structure de répertoire.- Les noms de package doivent être en minuscules. S'ils comportent plus d'un mot, ils doivent être utilisés comme sous-modules ou écrits en
snake_case
. - Les espaces ne sont pas autorisés.
Le nom complet est toujours utilisé dans les déclarations de packages.
Versions
Les versions doivent respecter le format suivant:
MAJOR.MINOR
La version MAJOR et la version MINOR doivent être un seul entier. HIDL utilise des règles de gestion sémantique des versions.
Importations
Une importation peut prendre l'un des trois formats suivants:
- Importations de l'intégralité du package:
import PACKAGE-NAME;
- Importations partielles:
import PACKAGE-NAME::UDT;
(ou, si le type importé se trouve dans le même package,import UDT;
- Importations de types uniquement:
import PACKAGE-NAME::types;
PACKAGE-NAME
suit le format décrit dans la section Noms de package. Le types.hal
du package actuel (s'il existe) est automatiquement importé (n'importez pas explicitement).
Noms complets
N'utilisez des noms complets pour une importation de type définie par l'utilisateur que si nécessaire.
Omettre PACKAGE-NAME
si le type d'importation se trouve dans le même package. Un nom de domaine complet ne doit pas contenir d'espaces. Exemple de nom complet:
android.hardware.nfc@1.0::INfcClientCallback
Dans un autre fichier sous android.hardware.nfc@1.0
, utilisez INfcClientCallback
pour désigner l'interface ci-dessus. Sinon, utilisez uniquement le nom complet.
Regrouper et organiser les importations
Ajoutez une ligne vide après la déclaration du package (avant les importations). Chaque importation doit occuper une seule ligne et ne doit pas être mise en retrait. Les importations sont regroupées dans l'ordre suivant:
- Autres packages
android.hardware
(utilisez des noms complets). - Autres packages
vendor.VENDOR
(utilisez des noms complets).- Chaque fournisseur doit être un groupe.
- Triez les fournisseurs par ordre alphabétique.
- Importations à partir d'autres interfaces du même package (utilisez des noms simples).
Insérez une ligne vide entre les groupes. Dans chaque groupe, triez les importations par ordre alphabétique. Exemple :
import android.hardware.nfc@1.0::INfc; import android.hardware.nfc@1.0::INfcClientCallback; /* Importing the whole module. */ import vendor.barvendor.bar@3.1; import vendor.foovendor.foo@2.2::IFooBar; import vendor.foovendor.foo@2.2::IFooFoo; import IBar; import IFoo;
Noms d'interface
Les noms d'interface doivent commencer par I
, suivi d'un nom UpperCamelCase
/PascalCase
. Une interface nommée IFoo
doit être définie dans le fichier IFoo.hal
. Ce fichier ne peut contenir que des définitions pour l'interface IFoo
(l'interface INAME
doit se trouver dans INAME.hal
).
Fonctions
Pour les noms de fonction, les arguments et les noms de variables de retour, utilisez lowerCamelCase
. Exemple :
open(INfcClientCallback clientCallback) generates (int32_t retVal); oneway pingAlive(IFooCallback cb);
Noms de champs de struct et d'union
Pour les noms de champ de struct ou d'union, utilisez lowerCamelCase
. Exemple :
struct FooReply { vec<uint8_t> replyData; }
Noms des types
Les noms de type font référence aux définitions de struct ou d'union, aux définitions de type enum et aux typedef
. Pour ces noms, utilisez UpperCamelCase
/PascalCase
. Exemples:
enum NfcStatus : int32_t { /*...*/ }; struct NfcData { /*...*/ };
Valeurs enum
Les valeurs d'énumération doivent être UPPER_CASE_WITH_UNDERSCORES
. Lorsque vous transmettez des valeurs d'énumération en tant qu'arguments de fonction et que vous les renvoyez en tant que valeurs renvoyées par la fonction, utilisez le type d'énumération réel (et non le type d'entier sous-jacent). Exemple :
enum NfcStatus : int32_t { HAL_NFC_STATUS_OK = 0, HAL_NFC_STATUS_FAILED = 1, HAL_NFC_STATUS_ERR_TRANSPORT = 2, HAL_NFC_STATUS_ERR_CMD_TIMEOUT = 3, HAL_NFC_STATUS_REFUSED = 4 };
Remarque:Le type sous-jacent d'un type d'énumération est déclaré explicitement après les deux-points. Comme il n'est pas dépendant du compilateur, l'utilisation du type d'énumération réel est plus claire.
Pour les noms complets des valeurs d'énumération, un deux-points est utilisé entre le nom du type d'énumération et le nom de la valeur d'énumération:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
Un nom complet ne doit pas contenir d'espaces. N'utilisez un nom complet que lorsque cela est nécessaire et omettez les parties inutiles. Exemple :
android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK
Commentaires
Pour un commentaire sur une seule ligne, //
, /* */
et /** */
sont acceptables.
// This is a single line comment /* This is also single line comment */ /** This is documentation comment */
-
Utilisez
/* */
pour les commentaires. Bien que HIDL prenne en charge//
pour les commentaires, leur utilisation est déconseillée, car ils n'apparaissent pas dans la sortie générée. - Utilisez
/** */
pour la documentation générée. Ils ne peuvent être appliqués qu'aux déclarations de type, de méthode, de champ et de valeur d'énumération. Exemple :/** Replied status */ enum TeleportStatus { /** Object entirely teleported. */ OK = 0, /** Methods return this if teleportation is not completed. */ ERROR_TELEPORT = 1, /** * Teleportation could not be completed due to an object * obstructing the path. */ ERROR_OBJECT = 2, ... }
- Commencez les commentaires multilignes par
/**
sur une ligne distincte. Utilisez*
au début de chaque ligne. Terminez le commentaire par*/
sur une ligne distincte, en alignant les astérisques. Exemple :/** * My multi-line * comment */
- La notice de licence et les journaux de modifications doivent commencer sur une nouvelle ligne avec
/*
(un seul astérisque), utiliser*
au début de chaque ligne et placer*/
sur la dernière ligne (les astérisques doivent s'aligner). Exemple :/* * Copyright (C) 2017 The Android Open Source Project * ... */ /* * Changelog: * ... */
Commentaires sur les fichiers
Commencez chaque fichier par la mention de licence appropriée. Pour les HAL principales, il doit s'agir de la licence Apache AOSP dans development/docs/copyright-templates/c.txt
.
N'oubliez pas de mettre à jour l'année et d'utiliser des commentaires multilignes de style /* */
, comme expliqué ci-dessus.
Vous pouvez placer une ligne vide après l'avis de licence, suivi d'informations sur le journal des modifications/la gestion des versions. Utilisez des commentaires multilignes de style /* */
comme expliqué ci-dessus, placez la ligne vide après le journal des modifications, puis suivez avec la déclaration de package.
Commentaires TODO
Les tâches à faire doivent inclure la chaîne TODO
en majuscules, suivie d'un deux-points. Exemple :
// TODO: remove this code before foo is checked in.
Les commentaires TODO ne sont autorisés que pendant le développement. Ils ne doivent pas exister dans les interfaces publiées.
Commentaires d'interface et de fonction (docstrings)
Utilisez /** */
pour les docstrings sur plusieurs lignes et sur une seule ligne. N'utilisez pas //
pour les docstrings.
Les chaînes de documentation des interfaces doivent décrire les mécanismes généraux de l'interface, la raison de la conception, l'objectif, etc. Les chaînes de documentation des fonctions doivent être spécifiques à la fonction (la documentation au niveau du package se trouve dans un fichier README du répertoire du package).
/** * IFooController is the controller for foos. */ interface IFooController { /** * Opens the controller. * * @return status HAL_FOO_OK if successful. */ open() generates (FooStatus status); /** Close the controller. */ close(); };
Vous devez ajouter des @param
et des @return
pour chaque paramètre/valeur renvoyée:
@param
doit être ajouté pour chaque paramètre. Il doit être suivi du nom du paramètre, puis de la docstring.@return
doit être ajouté pour chaque valeur renvoyée. Il doit être suivi du nom de la valeur renvoyée, puis de la docstring.
Exemple :
/** * Explain what foo does. * * @param arg1 explain what arg1 is * @param arg2 explain what arg2 is * @return ret1 explain what ret1 is * @return ret2 explain what ret2 is */ foo(T arg1, T arg2) generates (S ret1, S ret2);
Règles de mise en forme
Voici quelques règles générales de mise en forme:
- Longueur de la ligne Chaque ligne de texte ne doit pas dépasser 100 colonnes.
- Espaces blancs : Aucun espace en fin de ligne ; les lignes vides ne doivent pas contenir d'espaces.
- Espaces par rapport aux tabulations N'utilisez que des espaces.
- Taille du retrait. Utilisez 4 espaces pour les blocs et 8 espaces pour les retours à la ligne.
- Bracing (contrainte) À l'exception des valeurs d'annotation, une accolade ouverte se trouve sur la même ligne que le code précédent, mais une accolade fermée et la virgule suivante occupent toute la ligne. Exemple :
interface INfc { close(); };
Déclaration de package
La déclaration de package doit se trouver en haut du fichier après l'avis de licence, occuper toute la ligne et ne pas être mise en retrait. Les packages sont déclarés à l'aide du format suivant (pour la mise en forme des noms, consultez la section Noms de package):
package PACKAGE-NAME;
Exemple :
package android.hardware.nfc@1.0;
Déclarations de fonction
Le nom de la fonction, les paramètres, generates
et les valeurs de retour doivent se trouver sur la même ligne s'ils y trouvent leur place. Exemple :
interface IFoo { /** ... */ easyMethod(int32_t data) generates (int32_t result); };
S'ils ne tiennent pas sur la même ligne, essayez de placer les paramètres et les valeurs de retour au même niveau d'indentation et de distinguer generate
pour aider le lecteur à voir rapidement les paramètres et les valeurs de retour. Exemple :
interface IFoo { suchALongMethodThatCannotFitInOneLine(int32_t theFirstVeryLongParameter, int32_t anotherVeryLongParameter); anEvenLongerMethodThatCannotFitInOneLine(int32_t theFirstLongParameter, int32_t anotherVeryLongParameter) generates (int32_t theFirstReturnValue, int32_t anotherReturnValue); superSuperSuperSuperSuperSuperSuperLongMethodThatYouWillHateToType( int32_t theFirstVeryLongParameter, // 8 spaces int32_t anotherVeryLongParameter ) generates ( int32_t theFirstReturnValue, int32_t anotherReturnValue ); /* method name is even shorter than 'generates' */ foobar(AReallyReallyLongType aReallyReallyLongParameter, AReallyReallyLongType anotherReallyReallyLongParameter) generates (ASuperLongType aSuperLongReturnValue, // 4 spaces ASuperLongType anotherSuperLongReturnValue); }
Informations supplémentaires :
- Une parenthèse ouvrante se trouve toujours sur la même ligne que le nom de la fonction.
- Aucun espace entre le nom de la fonction et la parenthèse ouverte.
- Aucun espace entre les parenthèses et les paramètres sauf lorsqu'il y a des retours à la ligne entre eux.
- Si
generates
se trouve sur la même ligne que la parenthèse fermante précédente, utilisez un espace en amont. Sigenerates
se trouve sur la même ligne que la prochaine parenthèse ouverte, ajoutez un espace. - Alignez tous les paramètres et les valeurs renvoyées (si possible).
- L'indentation par défaut est de quatre espaces.
- Les paramètres mis en forme sont alignés sur les premiers paramètres de la ligne précédente. Sinon, ils sont mis en retrait de huit espaces.
Annotations
Utilisez le format suivant pour les annotations:
@annotate(keyword = value, keyword = {value, value, value})
Triez les annotations par ordre alphabétique et utilisez des espaces autour des signes égal. Exemple :
@callflow(key = value) @entry @exit
Assurez-vous qu'une annotation occupe toute la ligne. Exemples :
/* Good */ @entry @exit /* Bad */ @entry @exit
Si les annotations ne peuvent pas tenir sur une seule ligne, mettez-les en retrait de huit espaces. Exemple :
@annotate( keyword = value, keyword = { value, value }, keyword = value)
Si l'ensemble du tableau de valeurs ne peut pas tenir sur une même ligne, placez des sauts de ligne après les accolades ouvertes {
et après chaque virgule dans le tableau. Placez la parenthèse fermante immédiatement après la dernière valeur. N'utilisez pas les accolades si une seule valeur est définie.
Si l'ensemble du tableau de valeurs peut tenir sur une même ligne, n'utilisez pas d'espaces après les accolades ouvertes et avant les accolades fermées, et placez un espace après chaque virgule. Exemples :
/* Good */ @callflow(key = {"val", "val"}) /* Bad */ @callflow(key = { "val","val" })
Il ne doit pas y avoir de lignes vides entre les annotations et la déclaration de fonction. Exemples :
/* Good */ @entry foo(); /* Bad */ @entry foo();
Déclarations d'énumération
Respectez les règles suivantes pour les déclarations d'énumération:
- Si les déclarations d'énumération sont partagées avec un autre package, placez-les dans
types.hal
plutôt que de les intégrer dans une interface. - Utilisez un espace avant et après les deux-points, et un espace après le type sous-jacent avant l'accolade ouvrante.
- La dernière valeur d'énumération peut ne pas comporter de virgule supplémentaire.
Déclarations de struct
Respectez les règles suivantes pour les déclarations de struct:
- Si les déclarations de struct sont partagées avec un autre package, placez-les dans
types.hal
plutôt que de les intégrer dans une interface. - Placez un espace après le nom du type de struct et avant l'accolade ouvrante.
- Alignez les noms des champs (facultatif). Exemple :
struct MyStruct { vec<uint8_t> data; int32_t someInt; }
Déclarations de tableaux
N'insérez pas d'espaces entre les éléments suivants:
- Type d'élément et crochet d'ouverture
- Crochet ouvrant et taille du tableau.
- Taille du tableau et crochet fermant.
- Crochet fermant et crochet ouvrant suivant, s'il existe plusieurs dimensions.
Exemples :
/* Good */ int32_t[5] array; /* Good */ int32_t[5][6] multiDimArray; /* Bad */ int32_t [ 5 ] [ 6 ] array;
Vecteurs
N'insérez pas d'espaces entre les éléments suivants:
vec
et crochet gauche.- Chevron gauche et type d'élément (exception: le type d'élément est également un
vec
) - Type d'élément et crochet angulaire de fermeture (Exception: le type d'élément est également un
vec
).
Exemples :
/* Good */ vec<int32_t> array; /* Good */ vec<vec<int32_t>> array; /* Good */ vec< vec<int32_t> > array; /* Bad */ vec < int32_t > array; /* Bad */ vec < vec < int32_t > > array;