Der HIDL-Codestil ähnelt dem C++-Code im Android-Framework, mit Einzügen von vier Leerzeichen und Dateinamen in gemischter Groß- und Kleinschreibung. Paketdeklarationen, Importe und Dokumentzeichenfolgen ähneln denen in Java, mit geringfügigen Änderungen.
Die folgenden Beispiele für IFoo.hal
types.hal
veranschaulichen HIDL-Codestile und bieten schnelle Links zu Details zu jedem Stil ( IFooClientCallback.hal
, IBar.hal
und IBaz.hal
wurden weggelassen).
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; }; |
Regeln der Namensgebung
Funktionsnamen, Variablennamen und Dateinamen sollten beschreibend sein; Vermeiden Sie übermäßige Abkürzungen. Behandeln Sie Akronyme wie Wörter (verwenden Sie beispielsweise INfc
anstelle von INFC
).
Verzeichnisstruktur und Dateibenennung
Die Verzeichnisstruktur sollte wie folgt aussehen:
-
ROOT-DIRECTORY
-
MODULE
-
SUBMODULE
(optional, kann mehr als eine Ebene umfassen)-
VERSION
-
Android.mk
-
I INTERFACE_1 .hal
-
I INTERFACE_2 .hal
-
…
-
I INTERFACE_N .hal
-
types.hal
(optional)
-
-
-
-
Wo:
-
ROOT-DIRECTORY
lautet:-
hardware/interfaces
für Kern-HIDL-Pakete. -
vendor/ VENDOR /interfaces
für Anbieterpakete, wobeiVENDOR
sich auf einen SoC-Anbieter oder einen OEM/ODM bezieht.
-
-
MODULE
sollte ein kleingeschriebenes Wort sein, das das Subsystem beschreibt (z. B.nfc
). Wenn mehr als ein Wort benötigt wird, verwenden Sie verschachteltesSUBMODULE
. Es kann mehr als eine Verschachtelungsebene geben. -
VERSION
sollte genau dieselbe Version (major.minor) sein, wie unter Versionen beschrieben. -
I INTERFACE_X
sollte der Schnittstellenname mitUpperCamelCase
/PascalCase
(z. B.INfc
) sein, wie in Schnittstellennamen beschrieben.
Beispiel:
-
hardware/interfaces
-
nfc
-
1.0
-
Android.mk
-
INfc.hal
-
INfcClientCallback.hal
-
types.hal
-
-
-
Hinweis: Alle Dateien müssen über nicht ausführbare Berechtigungen verfügen (in Git).
Paketnamen
Paketnamen müssen das folgende FQN-Format (Fully Qualified Name) verwenden (bezeichnet als PACKAGE-NAME
):
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
Wo:
-
PACKAGE
ist das Paket, das demROOT-DIRECTORY
zugeordnet ist.PACKAGE
ist insbesondere:-
android.hardware
für HIDL-Kernpakete (Zuordnung zuhardware/interfaces
). -
vendor. VENDOR .hardware
für Anbieterpakete, wobeiVENDOR
sich auf einen SoC-Anbieter oder einen OEM/ODM bezieht (Zuordnung zuvendor/ VENDOR /interfaces
“).
-
-
MODULE [. SUBMODULE [. SUBMODULE […]]]@ VERSION
sind genau die gleichen Ordnernamen in der in Verzeichnisstruktur beschriebenen Struktur. - Paketnamen sollten in Kleinbuchstaben geschrieben werden. Wenn sie mehr als ein Wort lang sind, sollten die Wörter entweder als Submodule verwendet oder in
snake_case
geschrieben werden. - Es sind keine Leerzeichen erlaubt.
Der FQN wird immer in Paketdeklarationen verwendet.
Versionen
Versionen sollten das folgende Format haben:
MAJOR.MINOR
Sowohl die MAJOR als auch die MINOR Version sollten eine einzelne Ganzzahl sein. HIDL verwendet semantische Versionierungsregeln .
Importe
Ein Import hat eines der folgenden drei Formate:
- Importe ganzer Pakete:
import PACKAGE-NAME ;
- Teilimporte:
import PACKAGE-NAME :: UDT ;
(Oder, wenn sich der importierte Typ im selben Paket befindet,import UDT ;
- Nur-Typ-Importe:
import PACKAGE-NAME ::types;
Der PACKAGE-NAME
folgt dem Format in Paketnamen . Die types.hal
des aktuellen Pakets (falls vorhanden) wird automatisch importiert (nicht explizit importieren).
Vollqualifizierte Namen (FQNs)
Verwenden Sie für einen benutzerdefinierten Typimport nur dann vollständig qualifizierte Namen, wenn dies erforderlich ist. Lassen Sie PACKAGE-NAME
weg, wenn sich der Importtyp im selben Paket befindet. Ein FQN darf keine Leerzeichen enthalten. Beispiel für einen vollqualifizierten Namen:
android.hardware.nfc@1.0::INfcClientCallback
Beziehen Sie sich in einer anderen Datei unter android.hardware.nfc@1.0
auf die obige Schnittstelle als INfcClientCallback
. Andernfalls verwenden Sie nur den vollständig qualifizierten Namen.
Importe gruppieren und ordnen
Verwenden Sie nach der Paketdeklaration (vor den Importen) eine leere Zeile. Jeder Import sollte eine einzelne Zeile einnehmen und nicht eingerückt sein. Gruppieren Sie Importe in der folgenden Reihenfolge:
- Andere
android.hardware
Pakete (vollständig qualifizierte Namen verwenden). - Anderer
vendor. VENDOR
Pakete (vollständig qualifizierte Namen verwenden).- Jeder Anbieter sollte eine Gruppe sein.
- Bestellen Sie die Anbieter alphabetisch.
- Importiert von anderen Schnittstellen im selben Paket (einfache Namen verwenden).
Verwenden Sie eine Leerzeile zwischen den Gruppen. Sortieren Sie die Importe innerhalb jeder Gruppe alphabetisch. Beispiel:
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;
Schnittstellennamen
Schnittstellennamen müssen mit einem I
beginnen, gefolgt von einem UpperCamelCase
/ PascalCase
-Namen. In der Datei IFoo.hal
muss eine Schnittstelle mit dem Namen IFoo
definiert sein. Diese Datei kann nur Definitionen für die IFoo
Schnittstelle enthalten (die Schnittstelle I NAME
sollte in I NAME .hal
enthalten sein).
Funktionen
Verwenden Sie für Funktionsnamen, Argumente und Rückgabevariablennamen lowerCamelCase
. Beispiel:
open(INfcClientCallback clientCallback) generates (int32_t retVal); oneway pingAlive(IFooCallback cb);
Struktur-/Vereinigungsfeldnamen
Verwenden Sie für Struktur-/Union-Feldnamen lowerCamelCase
. Beispiel:
struct FooReply { vec<uint8_t> replyData; }
Geben Sie Namen ein
Typnamen beziehen sich auf Struktur-/Union-Definitionen, Enum-Typdefinitionen und typedef
. Verwenden Sie für diesen Namen UpperCamelCase
/ PascalCase
. Beispiele:
enum NfcStatus : int32_t { /*...*/ }; struct NfcData { /*...*/ };
Enum-Werte
Enum-Werte sollten UPPER_CASE_WITH_UNDERSCORES
sein. Wenn Sie Aufzählungswerte als Funktionsargumente übergeben und als Funktionsrückgaben zurückgeben, verwenden Sie den tatsächlichen Aufzählungstyp (nicht den zugrunde liegenden Ganzzahltyp). Beispiel:
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 };
Hinweis: Der zugrunde liegende Typ eines Aufzählungstyps wird explizit nach dem Doppelpunkt deklariert. Da es nicht vom Compiler abhängig ist, ist die Verwendung des tatsächlichen Aufzählungstyps klarer.
Bei vollständig qualifizierten Namen für Aufzählungswerte wird ein Doppelpunkt zwischen dem Namen des Aufzählungstyps und dem Namen des Aufzählungswerts verwendet:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
Ein vollständig qualifizierter Name darf keine Leerzeichen enthalten. Verwenden Sie nur bei Bedarf einen vollständig qualifizierten Namen und lassen Sie unnötige Teile weg. Beispiel:
android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK
Kommentare
Für einen einzeiligen Kommentar sind //
, /* */
und /** */
in Ordnung.
// This is a single line comment /* This is also single line comment */ /** This is documentation comment */
- Verwenden Sie
/* */
für Kommentare. Während HIDL//
für Kommentare unterstützt, wird davon abgeraten, da sie nicht in der generierten Ausgabe erscheinen. - Verwenden Sie
/** */
für die generierte Dokumentation. Diese können nur auf Typ-, Methoden-, Feld- und Enum-Wertdeklarationen angewendet werden. Beispiel:/** 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, ... }
- Beginnen Sie mehrzeilige Kommentare mit
/**
in einer separaten Zeile. Verwenden Sie*
am Anfang jeder Zeile. Beenden Sie den Kommentar mit*/
in einer separaten Zeile und richten Sie die Sternchen aus. Beispiel:/** * My multi-line * comment */
- Lizenzhinweise und Änderungsprotokolle sollten eine neue Zeile mit
/*
(einem einzelnen Sternchen) beginnen,*
am Anfang jeder Zeile verwenden und*/
allein in der letzten Zeile platzieren (Sternchen sollten ausgerichtet sein). Beispiel:/* * Copyright (C) 2017 The Android Open Source Project * ... */ /* * Changelog: * ... */
Dateikommentare
Beginnen Sie jede Datei mit dem entsprechenden Lizenzhinweis. Für Kern-HALs sollte dies die AOSP-Apache-Lizenz in development/docs/copyright-templates/c.txt
sein. Denken Sie daran, das Jahr zu aktualisieren und mehrzeilige Kommentare im Stil /* */
zu verwenden, wie oben erläutert.
Optional können Sie nach dem Lizenzhinweis eine Leerzeile einfügen, gefolgt von einem Änderungsprotokoll/Versionierungsinformationen. Verwenden Sie mehrzeilige Kommentare im Stil /* */
wie oben beschrieben, platzieren Sie die leere Zeile nach dem Änderungsprotokoll und folgen Sie dann mit der Paketdeklaration.
TODO-Kommentare
TODOs sollten die Zeichenfolge TODO
in Großbuchstaben gefolgt von einem Doppelpunkt enthalten. Beispiel:
// TODO: remove this code before foo is checked in.
TODO-Kommentare sind nur während der Entwicklung zulässig; Sie dürfen nicht in veröffentlichten Schnittstellen vorhanden sein.
Schnittstellen-/Funktionskommentare (Docstrings)
Verwenden Sie /** */
für mehrzeilige und einzeilige Dokumentzeichenfolgen. Verwenden Sie //
nicht für Dokumentzeichenfolgen.
Dokumentzeichenfolgen für Schnittstellen sollten allgemeine Mechanismen der Schnittstelle, Designprinzipien, Zweck usw. beschreiben. Dokumentzeichenfolgen für Funktionen sollten spezifisch für die Funktion sein (Dokumentation auf Paketebene befindet sich in einer README-Datei im Paketverzeichnis).
/** * 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(); };
Sie müssen @param
s und @return
s für jeden Parameter/Rückgabewert hinzufügen:
-
@param
muss für jeden Parameter hinzugefügt werden. Darauf sollte der Name des Parameters und dann die Dokumentzeichenfolge folgen. -
@return
muss für jeden Rückgabewert hinzugefügt werden. Darauf sollte der Name des Rückgabewerts und dann die Dokumentzeichenfolge folgen.
Beispiel:
/** * 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);
Formatierung
Zu den allgemeinen Formatierungsregeln gehören:
- Linienlänge . Jede Textzeile sollte maximal 100 Spalten lang sein.
- Leerzeichen . Keine abschließenden Leerzeichen in Zeilen; Leerzeilen dürfen keine Leerzeichen enthalten.
- Leerzeichen vs. Tabulatoren . Verwenden Sie nur Leerzeichen.
- Einzugsgröße . Verwenden Sie 4 Leerzeichen für Blöcke und 8 Leerzeichen für Zeilenumbrüche
- Versteifung . Mit Ausnahme von Anmerkungswerten steht eine öffnende geschweifte Klammer in derselben Zeile wie der vorangehende Code, aber eine schließende geschweifte Klammer und das folgende Semikolon nehmen die gesamte Zeile ein. Beispiel:
interface INfc { close(); };
Paketdeklaration
Die Paketdeklaration sollte am Anfang der Datei nach dem Lizenzhinweis stehen, die gesamte Zeile einnehmen und nicht eingerückt sein. Pakete werden im folgenden Format deklariert (Informationen zur Namensformatierung finden Sie unter Paketnamen ):
package PACKAGE-NAME;
Beispiel:
package android.hardware.nfc@1.0;
Funktionsdeklarationen
Funktionsname, Parameter, generates
und Rückgabewerte sollten in derselben Zeile stehen, wenn sie passen. Beispiel:
interface IFoo { /** ... */ easyMethod(int32_t data) generates (int32_t result); };
Wenn sie nicht in dieselbe Zeile passen, versuchen Sie, Parameter und Rückgabewerte auf derselben Einrückungsebene zu platzieren und generate
zu unterscheiden, damit der Leser die Parameter und Rückgabewerte schnell erkennen kann. Beispiel:
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); }
Weitere Details:
- Eine offene Klammer steht immer in derselben Zeile wie der Funktionsname.
- Zwischen dem Funktionsnamen und der offenen Klammer dürfen keine Leerzeichen stehen.
- Zwischen den Klammern und Parametern dürfen keine Leerzeichen stehen , es sei denn , dazwischen befinden sich Zeilenumbrüche.
- Wenn sich
generates
in derselben Zeile wie die vorherige schließende Klammer befindet, verwenden Sie ein vorangehendes Leerzeichen. Wenn sichgenerates
in derselben Zeile wie die nächste offene Klammer befindet, fügen Sie danach ein Leerzeichen ein. - Richten Sie alle Parameter und Rückgabewerte aus (falls möglich).
- Der Standardeinzug beträgt 4 Leerzeichen.
- Umschlossene Parameter werden an den ersten Parametern in der vorherigen Zeile ausgerichtet, andernfalls haben sie einen Einzug von 8 Leerzeichen.
Anmerkungen
Verwenden Sie für Anmerkungen das folgende Format:
@annotate(keyword = value, keyword = {value, value, value})
Sortieren Sie Anmerkungen in alphabetischer Reihenfolge und verwenden Sie Leerzeichen um Gleichheitszeichen. Beispiel:
@callflow(key = value) @entry @exit
Stellen Sie sicher, dass eine Anmerkung die gesamte Zeile einnimmt. Beispiele:
/* Good */ @entry @exit /* Bad */ @entry @exit
Wenn Anmerkungen nicht in dieselbe Zeile passen, rücken Sie sie mit 8 Leerzeichen ein. Beispiel:
@annotate( keyword = value, keyword = { value, value }, keyword = value)
Wenn das gesamte Wertearray nicht in dieselbe Zeile passt, setzen Sie Zeilenumbrüche nach den offenen Klammern {
und nach jedem Komma innerhalb des Arrays. Platzieren Sie die schließende Klammer unmittelbar nach dem letzten Wert. Setzen Sie die Klammern nicht, wenn nur ein Wert vorhanden ist.
Wenn das gesamte Wertearray in dieselbe Zeile passt, verwenden Sie nach den offenen und vor den schließenden Klammern keine Leerzeichen und verwenden Sie nach jedem Komma ein Leerzeichen. Beispiele:
/* Good */ @callflow(key = {"val", "val"}) /* Bad */ @callflow(key = { "val","val" })
Zwischen Anmerkungen und der Funktionsdeklaration dürfen KEINE Leerzeilen stehen. Beispiele:
/* Good */ @entry foo(); /* Bad */ @entry foo();
Enum-Deklarationen
Verwenden Sie die folgenden Regeln für Enum-Deklarationen:
- Wenn Enum-Deklarationen mit einem anderen Paket geteilt werden, fügen Sie die Deklarationen in
types.hal
ein, anstatt sie in eine Schnittstelle einzubetten. - Verwenden Sie ein Leerzeichen vor und nach dem Doppelpunkt und ein Leerzeichen nach dem zugrunde liegenden Typ vor der offenen Klammer.
- Der letzte Enumerationswert kann ein zusätzliches Komma enthalten oder auch nicht.
Strukturdeklarationen
Verwenden Sie die folgenden Regeln für Strukturdeklarationen:
- Wenn Strukturdeklarationen mit einem anderen Paket geteilt werden, fügen Sie die Deklarationen in
types.hal
ein, anstatt sie in eine Schnittstelle einzubetten. - Verwenden Sie nach dem Namen des Strukturtyps und vor der öffnenden Klammer ein Leerzeichen.
- Feldnamen ausrichten (optional). Beispiel:
struct MyStruct { vec<uint8_t> data; int32_t someInt; }
Array-Deklarationen
Setzen Sie zwischen Folgendem keine Leerzeichen:
- Elementtyp und offene eckige Klammer.
- Öffnen Sie die eckige Klammer und die Array-Größe.
- Arraygröße und schließende eckige Klammer.
- Schließen Sie die eckige Klammer und öffnen Sie die nächste eckige Klammer, wenn mehr als eine Dimension vorhanden ist.
Beispiele:
/* Good */ int32_t[5] array; /* Good */ int32_t[5][6] multiDimArray; /* Bad */ int32_t [ 5 ] [ 6 ] array;
Vektoren
Setzen Sie zwischen Folgendem keine Leerzeichen:
-
vec
und offene Winkelhalterung. - Öffnen Sie die spitze Klammer und den Elementtyp ( Ausnahme: Elementtyp ist auch ein
vec
). - Elementtyp und schließende spitze Klammer ( Ausnahme: Elementtyp ist auch ein
vec
) .
Beispiele:
/* 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;