Guida di stile del codice

Lo stile del codice HIDL assomiglia al codice C++ nel framework Android, con e nomi file con lettere maiuscole e minuscole. Dichiarazioni relative al pacchetto, importazioni e docstring sono simili a quelli in Java, con qualche lieve modifica.

I seguenti esempi per IFoo.hal e types.hal illustrano gli stili di codice HIDL e forniscono link rapidi a dettagli su ogni stile (IFooClientCallback.hal, IBar.hal e IBaz.hal sono stati omessi).

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;
};

Convenzioni di denominazione

I nomi delle funzioni, delle variabili e dei file devono essere descrittivi; evitare abbreviazione eccessiva. Tratta gli acronimi come parole (ad esempio, usa INfc di INFC).

Struttura della directory e denominazione dei file

La struttura della directory dovrebbe essere simile alla seguente:

  • ROOT-DIRECTORY
    • MODULE
      • SUBMODULE (facoltativo, può essere più di uno) livello)
        • VERSION
          • Android.mk
          • IINTERFACE_1.hal
          • IINTERFACE_2.hal
          • IINTERFACE_N.hal
          • types.hal (facoltativo)

Dove:

  • ROOT-DIRECTORY è:
    • hardware/interfaces per i pacchetti HIDL principali.
    • vendor/VENDOR/interfaces per i pacchetti di fornitori, dove VENDOR si riferisce a un fornitore di SoC o OEM/ODM.
  • MODULE deve essere una parola minuscola che descrive del sottosistema (ad esempio, nfc). Se sono necessarie più parole, usa nidificato SUBMODULE. Può esserci più di un livello di la nidificazione.
  • VERSION deve essere esattamente la stessa versione (major.minor) come descritto in Versioni.
  • IINTERFACE_X deve essere il nome dell'interfaccia con UpperCamelCase/PascalCase (ad es. INfc) come descritto in Nomi delle interfacce.

Esempio:

  • hardware/interfaces
    • nfc
      • 1.0
        • Android.mk
        • INfc.hal
        • INfcClientCallback.hal
        • types.hal

Nota:tutti i file non devono essere eseguibili autorizzazioni (in Git).

Nomi dei pacchetti

I nomi dei pacchetti devono utilizzare il seguente nome completo (FQN) (denominato PACKAGE-NAME):

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

Dove:

  • PACKAGE è il pacchetto mappato ROOT-DIRECTORY. In particolare, PACKAGE è:
    • android.hardware per i pacchetti HIDL principali (mappatura a hardware/interfaces).
    • vendor.VENDOR.hardware per i pacchetti di fornitori, dove VENDOR si riferisce a un fornitore di SoC o a un OEM/ODM (mappatura a vendor/VENDOR/interfaces).
  • MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION gli stessi nomi di cartelle nella struttura descritta Struttura della directory.
  • I nomi dei pacchetti devono essere in minuscolo. Se sono composte da più di una parola, il le parole devono essere usate come sottomoduli o scritte in snake_case.
  • Non sono ammessi spazi.

Il nome di dominio completo viene sempre utilizzato nelle dichiarazioni relative ai pacchetti.

Versioni

Le versioni devono avere il seguente formato:

MAJOR.MINOR

Sia la versione MAJOR che la versione MINOR devono essere un'unica versione numero intero. L'HIDL usa la semantica di controllo delle versioni.

Importazioni

Un'importazione prevede uno dei seguenti tre formati:

  • Importazioni di un intero pacchetto: import PACKAGE-NAME;
  • Importazioni parziali: import PACKAGE-NAME::UDT; (o, se hai importato è nello stesso pacchetto,import UDT;
  • Importazioni solo tipi: import PACKAGE-NAME::types;

PACKAGE-NAME segue il formato in Nomi dei pacchetti. Il valore del pacchetto types.hal (se esistente) viene importato automaticamente (non importare esplicitamente).

Nomi completi

Utilizza nomi completi per un'importazione di tipo definita dall'utente solo quando necessario. Ometti PACKAGE-NAME se il tipo di importazione è dello stesso pacchetto. Un nome di dominio non deve contenere spazi. Esempio di nome completo:

android.hardware.nfc@1.0::INfcClientCallback

In un altro file in android.hardware.nfc@1.0, fai riferimento alla sopra l'interfaccia come INfcClientCallback. Altrimenti, utilizza solo nome completo.

Raggruppamento e ordinamento delle importazioni

Usa una riga vuota dopo la dichiarazione relativa al pacchetto (prima delle importazioni). Ogni importazione deve occupare una sola riga e non deve essere rientrato. Raggruppa le importazioni nel nel seguente ordine:

  1. Altri pacchetti android.hardware (utilizza nomi completi).
  2. Altri pacchetti vendor.VENDOR (utilizza i pacchetti completi nomi).
    • Ogni fornitore deve essere un gruppo.
    • Ordina i fornitori in ordine alfabetico.
  3. Importazioni da altre interfacce nello stesso pacchetto (utilizza nomi semplici).

Utilizza una riga vuota tra i gruppi. All'interno di ogni gruppo, ordina le importazioni in ordine alfabetico. Esempio:

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;

Nomi delle interfacce

I nomi delle interfacce devono iniziare con un I, seguito da un Nome UpperCamelCase/PascalCase. Un'interfaccia con un nome IFoo deve essere definito nel file IFoo.hal. Questo file può contenere le definizioni solo per l'interfaccia IFoo (l'interfaccia INAME deve essere in INAME.hal).

Funzioni

Per nomi di funzioni, argomenti e nomi di variabili restituiti, utilizza lowerCamelCase. Esempio:

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

Nomi dei campi di struct e Union

Per i nomi dei campi di struct o union, utilizza lowerCamelCase. Esempio:

struct FooReply {
    vec<uint8_t> replyData;
}

Nomi dei tipi

I nomi dei tipi si riferiscono a definizioni di struct o union, enum e typedef Per questo nome, utilizza UpperCamelCase/PascalCase. Esempi:

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

Valori enum

I valori enum devono essere UPPER_CASE_WITH_UNDERSCORES. Al superamento valori enum come argomenti di funzione e li restituisce come ritorni di funzione, utilizza il tipo di enum effettivo (non il tipo intero sottostante). Esempio:

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
};

Nota: il tipo sottostante di un tipo enum è dichiarate esplicitamente dopo i due punti. Poiché non dipende dal compilatore, l'utilizzo della funzione il tipo di enum effettivo è più chiaro.

Per i nomi completi per i valori enum, vengono utilizzati i due punti tra il nome del tipo enum e il nome del valore enum:

PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME

Il nome completo non deve contenere spazi. Utilizza un modello completo solo quando necessario e ometti le parti non necessarie. Esempio:

android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK

Commenti

Per un commento di una sola riga, //, /* */ e /** */ vanno bene.

// This is a single line comment
/* This is also single line comment */
/** This is documentation comment */
  • Utilizza /* */ per i commenti. Anche se HIDL supporta // per i commenti, sono sconsigliati perché non appaiono nell'output generato.
  • Usa /** */ per la documentazione generata. Possono essere applicati solo per le dichiarazioni di valore di tipo, metodo, campo ed enum. Esempio:
    /** 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,
        ...
    }
    
  • Inizia commenti su più righe con /** su una riga separata. Utilizza * all'inizio di ogni riga. Termina il commento con */ su una riga separata, allineando gli asterischi. Esempio:
    /**
     * My multi-line
     * comment
     */
    
  • Gli avvisi di licenza e i log delle modifiche devono iniziare una nuova riga con /* (un singolo asterisco), utilizza * all'inizio di ogni riga e posiziona */ nell'ultima riga, tutto da solo (gli asterischi devono essere allineati). Esempio:
    /*
     * Copyright (C) 2017 The Android Open Source Project
     * ...
     */
    
    /*
     * Changelog:
     * ...
     */
    

Commenti del file

Inizia ogni file con l'avviso di licenza appropriato. Per gli HAL principali, deve essere la licenza Apache AOSP development/docs/copyright-templates/c.txt Ricordati di aggiornare l'anno e di usare commenti su più righe in stile /* */ come spiegato in precedenza.

Se vuoi, puoi inserire una riga vuota dopo la notifica sulla licenza, seguita da un log delle modifiche/informazioni sul controllo delle versioni. Usa lo stile /* */ ai commenti su più righe come spiegato in precedenza, metti la riga vuota dopo il Changelog, quindi segui la dichiarazione relativa al pacchetto.

Commenti TODO

I TODO devono includere la stringa TODO in maiuscolo, seguita da un I due punti. Esempio:

// TODO: remove this code before foo is checked in.

I commenti TODO sono consentiti solo durante lo sviluppo; devono non esistono nelle interfacce pubblicate.

Commenti dell'interfaccia e delle funzioni (docstring)

Utilizza /** */ per docstring multiriga e a riga singola. Non utilizzare // per docstring.

I docstring per le interfacce devono descrivere i meccanismi generali del dell'interfaccia, della logica della progettazione, dello scopo ecc. I docstring per le funzioni dovrebbero essere specifica per la funzione (la documentazione a livello di pacchetto si trova in un file README nella directory dei pacchetti).

/**
 * 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();
};

Devi aggiungere @param e @return per ogni valore parametro/restituito:

  • È necessario aggiungere @param per ogni parametro. Dovrebbe essere seguito dal nome del parametro e poi da docstring.
  • È necessario aggiungere @return per ogni valore restituito. it deve essere seguito dal nome del valore restituito e da docstring.

Esempio:

/**
 * 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);

Regole di formattazione

Le regole di formattazione generali includono:

  • Lunghezza linea. Ogni riga di testo deve essere al massimo 100 colonne.
  • Spazi vuoti. Nessuno spazio vuoto finale sulle righe. righe vuote non devono contenere spazi vuoti.
  • Spazi e schede. Utilizza solo gli spazi.
  • Dimensioni rientro. Usa 4 spazi per i blocchi e 8 spazi per l'aggregazione a capo
  • Bracing. Fatta eccezione per l'annotazione , una parentesi graffa aperta si inserisce nella stessa riga della precedente ma una parentesi graffa di chiusura e il seguente punto e virgola occupa l'intera riga. Esempio:
    interface INfc {
        close();
    };
    

Dichiarazione relativa al pacco

La dichiarazione relativa al pacco deve essere posizionata nella parte superiore del file, dopo la licenza dovrebbe occupare l'intera riga e non deve essere rientrato. I pacchetti sono dichiarata utilizzando il seguente formato (per la formattazione del nome, consulta Nomi dei pacchetti):

package PACKAGE-NAME;

Esempio:

package android.hardware.nfc@1.0;

Dichiarazioni di funzione

Il nome della funzione, i parametri, generates e i valori restituiti devono devono essere sulla stessa linea, se c'è spazio. Esempio:

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

Se non rientrano nella stessa riga, prova a inserire i parametri e valori nello stesso livello di rientro e distinguere generate per il lettore vede rapidamente i parametri e restituisce i valori. Esempio:

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);
}

Ulteriori dettagli:

  • Una parentesi aperta è sempre sulla stessa riga del nome della funzione.
  • Non devono esserci spazi tra il nome della funzione e le parentesi aperte.
  • Non utilizzare spazi tra parentesi e parametri, tranne quando sono presenti sono feed di riga tra di loro.
  • Se generates è sulla stessa riga della chiusura precedente parentesi, utilizza uno spazio precedente. Se generates è nello stesso posto come parentesi aperta successiva, segui uno spazio.
  • Allinea tutti i parametri e restituisci i valori (se possibile).
  • Il rientro predefinito è di 4 spazi.
  • I parametri con wrapping sono allineati ai primi parametri della riga precedente, altrimenti avranno un rientro di 8 spazi.

Annotazioni

Utilizza il seguente formato per le annotazioni:

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

Ordina le annotazioni in ordine alfabetico e utilizza gli spazi attorno ai segni di uguale. Esempio:

@callflow(key = value)
@entry
@exit

Assicurati che un'annotazione occupi l'intera riga. Esempi:

/* Good */
@entry
@exit

/* Bad */
@entry @exit

Se le annotazioni non possono rientrare nella stessa riga, applica un rientro con 8 spazi. Esempio:

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

Se l'intero array di valori non può essere nella stessa riga, inserisci le interruzioni di riga dopo parentesi graffe aperte { e dopo ogni virgola all'interno dell'array. Chiusura del luogo parentesi immediatamente dopo l'ultimo valore. Non mettere le parentesi graffe se c'è un solo valore.

Se l'intero array di valori può essere nella stessa riga, non utilizzare spazi dopo parentesi graffe aperte e prima di chiudere le parentesi graffe e utilizza uno spazio dopo ogni virgola. Esempi:

/* Good */
@callflow(key = {"val", "val"})

/* Bad */
@callflow(key = { "val","val" })

NON devono esserci righe vuote tra le annotazioni e la funzione dichiarazione. Esempi:

/* Good */
@entry
foo();

/* Bad */
@entry

foo();

Dichiarazioni enum

Utilizza le seguenti regole per le dichiarazioni enum:

  • Se le dichiarazioni enum vengono condivise con un altro pacchetto, inseriscile in types.hal anziché incorporarlo all'interno di un'interfaccia.
  • Utilizza uno spazio prima e dopo i due punti e uno spazio dopo il tipo sottostante. prima della parentesi graffa aperta.
  • L'ultimo valore enum potrebbe non contenere una virgola aggiuntiva.

Dichiarazioni struct

Utilizza le seguenti regole per le dichiarazioni struct:

  • Se le dichiarazioni struct vengono condivise con un altro pacchetto, inserisci le dichiarazioni in types.hal anziché incorporarlo all'interno di un'interfaccia.
  • Utilizza uno spazio dopo il nome del tipo di struct prima della parentesi graffa aperta.
  • (Facoltativo) Allinea i nomi dei campi. Esempio:
    struct MyStruct {
        vec<uint8_t>   data;
        int32_t        someInt;
    }
    

Dichiarazioni di array

Non inserire spazi tra i seguenti elementi:

  • Tipo di elemento e parentesi quadra aperta.
  • Parentesi quadra aperta e dimensione dell'array.
  • Dimensioni dell'array e parentesi quadra chiusa.
  • Parentesi quadra chiusa e parentesi quadra aperta successiva, se più di una dimensione esistente.

Esempi:

/* Good */
int32_t[5] array;

/* Good */
int32_t[5][6] multiDimArray;

/* Bad */
int32_t [ 5 ] [ 6 ] array;

Vettori

Non inserire spazi tra i seguenti elementi:

  • vec e parentesi angolare aperta.
  • Parentesi angolare aperta e tipo di elemento (Eccezione: il tipo di elemento è anche un vec).
  • Tipo di elemento e parentesi angolare chiusa (Eccezione: il tipo di elemento è anche un vec).

Esempi:

/* 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;