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, doveVENDOR
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 nidificatoSUBMODULE
. 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 conUpperCamelCase
/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 mappatoROOT-DIRECTORY
. In particolare,PACKAGE
è:android.hardware
per i pacchetti HIDL principali (mappatura ahardware/interfaces
).vendor.VENDOR.hardware
per i pacchetti di fornitori, doveVENDOR
si riferisce a un fornitore di SoC o a un OEM/ODM (mappatura avendor/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:
- Altri pacchetti
android.hardware
(utilizza nomi completi). - Altri pacchetti
vendor.VENDOR
(utilizza i pacchetti completi nomi).- Ogni fornitore deve essere un gruppo.
- Ordina i fornitori in ordine alfabetico.
- 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. Segenerates
è 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;