Guide de style du code

Le style de code HIDL ressemble au code C++ du framework Android, avec quatre espaces retraits et noms de fichiers avec casse mixte. Déclarations, importations et docstrings de packages sont semblables à celles de Java, avec de légères modifications.

Les exemples suivants pour IFoo.hal et types.hal illustrer les styles de code HIDL et fournir des liens rapides vers des détails 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 fonctions, de variables et de noms de fichiers doivent être descriptifs. éviter sur l'abréviation. Traitez les acronymes comme des mots (par exemple, utilisez INfc à la place). sur INFC).

Structure de répertoire et nommage de fichier

La structure de répertoires doit se présenter comme suit:

  • ROOT-DIRECTORY
    • MODULE
      • SUBMODULE (facultatif, il peut y avoir plusieurs niveau)
        • VERSION
          • Android.mk
          • IINTERFACE_1.hal
          • IINTERFACE_2.hal
          • IINTERFACE_N.hal
          • types.hal (facultatif)

Où :

  • ROOT-DIRECTORY est:
    • hardware/interfaces pour les packages HIDL de base.
    • vendor/VENDOR/interfaces pour les packages des fournisseurs où VENDOR fait référence à un fournisseur de SoC ou OEM/ODM.
  • MODULE doit être un mot en minuscules décrivant le sous-système (par exemple, nfc). Si plusieurs mots sont nécessaires, utilisez SUBMODULE imbriqué. Il peut y avoir plusieurs niveaux ou l'imbrication.
  • VERSION doit correspondre exactement à la même version (major.minor), comme indiqué dans la section Versions.
  • IINTERFACE_X doit être le nom de l'interface avec UpperCamelCase/PascalCase (par exemple, INfc) comme indiqué 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 contenir des fichiers non exécutables (dans Git).

Noms des packages

Les noms de package doivent utiliser le nom complet suivant : (FQN) (appelé PACKAGE-NAME):

PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION

Où :

  • PACKAGE est le package correspondant au ROOT-DIRECTORY En particulier, PACKAGE est:
    • android.hardware pour les packages HIDL de base (mappé sur hardware/interfaces).
    • vendor.VENDOR.hardware pour les packages des fournisseurs, où VENDOR fait référence à un fournisseur de SoC ou à un OEM/ODM (mappage à vendor/VENDOR/interfaces).
  • MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION sont exactement les mêmes noms de dossiers dans la structure décrite dans Structure des répertoires :
  • Les noms des packages doivent être en minuscules. S'ils comportent plusieurs mots, le les mots doivent être utilisés comme sous-modules ou écrits dans snake_case.
  • Les espaces ne sont pas autorisés.

Le nom de domaine complet est toujours utilisé dans les déclarations de package.

Versions

Les versions doivent respecter le format suivant:

MAJOR.MINOR

Les versions MAJOR et MINOR doivent être uniques entier. HIDL utilise des de gestion des versions.

Importations

Une importation a l'un des trois formats suivants:

  • Importations du package entier: import PACKAGE-NAME;
  • Importations partielles: import PACKAGE-NAME::UDT; (ou, si le fichier se trouve dans le même package,import UDT;
  • Importations de types uniquement: import PACKAGE-NAME::types;

PACKAGE-NAME suit le format de Noms des packages. Le package actuel types.hal (s'il existe) est importé automatiquement (ne pas importer) explicitement).

Noms complets

N'utilisez des noms complets pour une importation de type défini par l'utilisateur qu'en cas de nécessité. Omettez PACKAGE-NAME si le type d'importation est le même d'un 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, reportez-vous au ci-dessus en tant que INfcClientCallback. Sinon, utilisez uniquement la nom complet.

Regrouper et trier les importations

Utilisez 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 en retrait. Les importations de groupes dans dans l'ordre suivant:

  1. Autres packages android.hardware (utilisez des noms complets).
  2. Autres packages vendor.VENDOR (utilisez les formats complets noms).
    • Chaque fournisseur doit être un groupe.
    • Classez les fournisseurs par ordre alphabétique.
  3. Importation depuis d'autres interfaces du même package (utilisez des noms simples).

Utilisez une ligne vide entre les groupes. Dans chaque groupe, trier 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 des interfaces

Les noms d'interface doivent commencer par I, suivi d'un Nom UpperCamelCase/PascalCase. Une interface portant un nom IFoo doit être défini dans le fichier IFoo.hal. Ce fichier ne peut contenir des définitions que pour l'interface IFoo (interface INAME doit se trouver dans INAME.hal).

Fonctions

Pour les noms de fonction, les arguments et les noms des variables de retour, utilisez lowerCamelCase Exemple :

open(INfcClientCallback clientCallback) generates (int32_t retVal);
oneway pingAlive(IFooCallback cb);

Noms des champs de structure et d'union

Pour les noms de champs de structure ou d'union, utilisez lowerCamelCase. Exemple :

struct FooReply {
    vec<uint8_t> replyData;
}

Noms des types

Les noms de type font référence à des définitions de structure ou d'union, des définitions de type d'énumération et typedefs. Pour ces noms, utilisez UpperCamelCase/PascalCase. Exemples:

enum NfcStatus : int32_t {
    /*...*/
};
struct NfcData {
    /*...*/
};

Valeurs enum

Les valeurs enum doivent être UPPER_CASE_WITH_UNDERSCORES. Lors de la transmission en tant qu'arguments de fonction et en les renvoyant sous forme de résultats de fonction, utilisez le type d'énumération réel (pas 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 d'un compilateur, l'utilisation de la classe le type d'énumération réel est plus clair.

Pour les noms complets des valeurs enum, le signe 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

Le nom complet ne doit pas contenir d'espaces. Utilisez un nom complet nom uniquement si 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 acceptés.

// This is a single line comment
/* This is also single line comment */
/** This is documentation comment */
  • Utilisez /* */ pour les commentaires. Alors que HIDL prend en charge // pour les commentaires, ils sont déconseillés car ils n'apparaissent pas dans la sortie générée.
  • Utilisez /** */ pour la documentation générée. Ceux-ci peuvent être appliqués uniquement pour les 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 sur plusieurs lignes 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 notification de licence et les journaux de modifications doivent commencer par une nouvelle ligne avec /* (un seul astérisque), utilisez * au début de chaque ligne et placez */, tout seul sur la dernière ligne (les astérisques doivent s'aligner). Exemple:
    /*
     * Copyright (C) 2017 The Android Open Source Project
     * ...
     */
    
    /*
     * Changelog:
     * ...
     */
    

Commentaires sur le fichier

Commencez chaque fichier par la mention de licence appropriée. Pour les HAL principales, doit être la licence Apache AOSP development/docs/copyright-templates/c.txt N'oubliez pas de modifier l'année et d'utiliser des commentaires multilignes de style /* */ comme expliqué ci-dessus.

Vous pouvez éventuellement placer une ligne vide après la notification de licence, suivie par des informations de journal de modifications/de gestion des versions. Utiliser le style /* */ comme expliqué ci-dessus, placez la ligne vide après la balise journal des modifications, puis suivez la déclaration de package.

TODO de commentaires

Les tâches à effectuer doivent inclure la chaîne TODO tout 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. il doit n'existent pas dans les interfaces publiées.

Commentaires sur l'interface et la fonction (docstrings)

Utilisez /** */ pour les docstrings multilignes et monolignes. Ne pas utiliser // pour les docstrings.

Les docstrings pour les interfaces doivent décrire les mécanismes généraux l'interface, la logique de conception, l'objectif, etc. Les Docstrings pour les fonctions doivent être propre à la fonction (la documentation au niveau du paquet se trouve dans un fichier README le 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 éléments @param et @return pour chacun paramètre/valeur renvoyée:

  • Vous devez ajouter @param pour chaque paramètre. Il doit s'agir 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

Les règles générales de mise en forme incluent les suivantes:

  • Longueur de ligne. Chaque ligne de texte ne doit pas dépasser 100 colonnes
  • Espaces blancs : Aucun espace blanc final sur les lignes lignes vides ne doit pas contenir d'espaces blancs.
  • Espaces ou onglets : N'utilisez que des espaces.
  • Taille du retrait : Utilisez 4 espaces pour les blocs et 8 espaces pour les retours à la ligne
  • Braces : À l'exception des annotations , une accolade open s'ajoute à la ligne précédente mais une accolade fermante et le point-virgule suivant occupent toute la ligne. Exemple:
    interface INfc {
        close();
    };
    

Déclaration de colis

La déclaration de package doit se trouver en haut du fichier, après la licence doit occuper toute la ligne et ne doit pas être en retrait. Les packages sont déclaré à l'aide du format suivant (pour en savoir plus sur la mise en forme du nom, consultez Noms des packages):

package PACKAGE-NAME;

Exemple :

package android.hardware.nfc@1.0;

Déclarations de fonctions

Le nom de la fonction, les paramètres, generates et les valeurs de retour doivent être sur la même ligne s’ils s’adaptent. Exemple :

interface IFoo {
    /** ... */
    easyMethod(int32_t data) generates (int32_t result);
};

S'ils ne tiennent pas sur la même ligne, essayez de placer des paramètres et de renvoyer valeurs au même niveau de retrait et à distinguer generate pour au lecteur de voir rapidement les paramètres et les valeurs renvoyées. 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 ouverte 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.
  • Pas d'espace entre les parenthèses et les paramètres, sauf lorsqu'il existe sont des sauts de ligne entre eux.
  • Si generates se trouve sur la même ligne que la ligne de fermeture précédente parenthèse, utilisez un espace qui précède. Si generates est identique comme parenthèse suivante, faites suivre d’un espace.
  • Alignez tous les paramètres et les valeurs renvoyées (si possible).
  • Le retrait par défaut est de 4 espaces.
  • Les paramètres encapsulés sont alignés sur les premiers paramètres de la ligne précédente, sinon, ils ont un retrait de 8 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

S'assurer qu'une annotation occupe la totalité de la ligne. Exemples :

/* Good */
@entry
@exit

/* Bad */
@entry @exit

Si les annotations ne peuvent pas tenir sur la même ligne, mettez en retrait 8 espaces. Exemple :

@annotate(
        keyword = value,
        keyword = {
                value,
                value
        },
        keyword = value)

Si le tableau de valeurs entier ne peut pas tenir sur la même ligne, placez des sauts de ligne après accolades { et après chaque virgule dans le tableau. Fermeture du lieu parenthèse juste après la dernière valeur. Ne mettez pas d'accolades s'il y a une seule valeur.

Si le tableau de valeurs entier peut tenir sur la même ligne, n'utilisez pas d'espaces après les accolades ouvertes et avant les accolades fermantes, et utilisez 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 fonction. la déclaration. Exemples :

/* Good */
@entry
foo();

/* Bad */
@entry

foo();

Déclarations d'énumération

Utilisez 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 d'être intégré 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.
  • Il est possible que la dernière valeur d'énumération ne comporte pas de virgule supplémentaire.

Déclarations de structure

Utilisez les règles suivantes pour les déclarations struct:

  • Si les déclarations struct sont partagées avec un autre package, placez les déclarations dans types.hal plutôt que d'être intégré dans une interface.
  • Ajoutez un espace après le nom du type de structure avant l'accolade ouvrante.
  • Aligne les noms des champs (facultatif). Exemple:
    struct MyStruct {
        vec<uint8_t>   data;
        int32_t        someInt;
    }
    

Déclarations de tableau

N'insérez pas d'espaces entre les éléments suivants:

  • Type d'élément et crochet ouvert.
  • Crochet ouvert et taille du tableau.
  • Taille du tableau et crochet fermant
  • Crochet fermé et crochet ouvrant suivant, s'il y en a plusieurs existe.

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 chevron ouvert.
  • Crochet ouvrant et type d'élément (Exception: le type d'élément est également vec).
  • Type d'élément et chevron fermant (Exception: le type d'élément est également 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;