Der HIDL-Codestil ähnelt C++-Code im Android-Framework, mit Einzügen aus 4 Leerzeichen und Dateinamen mit gemischten Groß- und Kleinschreibung. Paketdeklarationen, Importe und Docstrings ähneln denen in Java, mit geringfügigen Änderungen.
Die folgenden Beispiele für IFoo.hal
und 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 zu starke Abkürzungen. Akronyme als Wörter behandeln (z. B. 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
ist:-
hardware/interfaces
für Kern-HIDL-Pakete. -
vendor/ VENDOR /interfaces
für Anbieterpakete, wobei sichVENDOR
auf einen SoC-Anbieter oder einen OEM/ODM bezieht.
-
-
MODULE
sollte ein Wort in Kleinbuchstaben 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 die gleiche Version (major.minor) sein, wie in 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 (in Git) verfügen.
Paketnamen
Paketnamen müssen das folgende vollqualifizierte Namensformat (FQN) verwenden (als PACKAGE-NAME
bezeichnet):
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
Wo:
-
PACKAGE
ist das Paket, das demROOT-DIRECTORY
zugeordnet ist.PACKAGE
ist insbesondere:-
android.hardware
für Kern-HIDL-Pakete (Zuordnung zuhardware/interfaces
). -
vendor. VENDOR .hardware
für Anbieterpakete, wobei sichVENDOR
auf einen SoC-Anbieter oder einen OEM/ODM bezieht (Zuordnung zuvendor/ VENDOR /interfaces
).
-
-
MODULE [. SUBMODULE [. SUBMODULE […]]]@ VERSION
sind die exakt gleichen Ordnernamen in der unter 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. - Leerzeichen sind nicht erlaubt.
Die 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:
- Import von ganzen Paketen:
import PACKAGE-NAME ;
- Teilimporte:
import PACKAGE-NAME :: UDT ;
(oder, wenn sich der importierte Typ im selben Paket befindet,import UDT ;
- Nur-Typen-Importe:
import PACKAGE-NAME ::types;
Der PACKAGE-NAME
folgt dem Format in Paketnamen . Die Datei " types.hal
" des aktuellen Pakets (falls vorhanden) wird automatisch importiert (importieren Sie sie nicht explizit).
Vollqualifizierte Namen (FQNs)
Verwenden Sie nur bei Bedarf vollständig qualifizierte Namen für einen benutzerdefinierten Typimport. Lassen Sie PACKAGE-NAME
wenn sich der Importtyp im selben Paket befindet. Eine FQN darf keine Leerzeichen enthalten. Beispiel für einen vollqualifizierten Namen:
android.hardware.nfc@1.0::INfcClientCallback
Verweisen Sie in einer anderen Datei unter android.hardware.nfc@1.0
auf die obige Schnittstelle als INfcClientCallback
. Verwenden Sie andernfalls nur den vollständig qualifizierten Namen.
Gruppieren und Bestellen von Importen
Verwenden Sie eine Leerzeile nach der Paketdeklaration (vor den Importen). Jeder Import sollte eine einzelne Zeile einnehmen und nicht eingerückt sein. Gruppieren Sie Importe in der folgenden Reihenfolge:
- Andere
android.hardware
Pakete (verwenden Sie vollständig qualifizierte Namen). - Anderer
vendor. VENDOR
Pakete (verwenden Sie vollständig qualifizierte Namen).- Jeder Anbieter sollte eine Gruppe sein.
- Anbieter alphabetisch ordnen.
- Importe von anderen Schnittstellen im selben Paket (verwenden Sie einfache Namen).
Verwenden Sie eine Leerzeile zwischen 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 werden. Diese Datei kann nur Definitionen für die IFoo
-Schnittstelle enthalten (die Schnittstelle I NAME
sollte sich in I NAME .hal
).
Funktionen
Verwenden Sie für Funktionsnamen, Argumente und Rückgabevariablennamen lowerCamelCase
. Beispiel:
open(INfcClientCallback clientCallback) generates (int32_t retVal); oneway pingAlive(IFooCallback cb);
Struktur-/Union-Feldnamen
Verwenden Sie für Struktur-/Vereinigungsfeldnamen lowerCamelCase
. Beispiel:
struct FooReply { vec<uint8_t> replyData; }
Geben Sie Namen ein
Typnamen beziehen sich auf Struct/Union-Definitionen, Enum-Typdefinitionen und typedef
s. Verwenden Sie für diese Namen UpperCamelCase
/ PascalCase
. Beispiele:
enum NfcStatus : int32_t { /*...*/ }; struct NfcData { /*...*/ };
Enum-Werte
Enum-Werte sollten UPPER_CASE_WITH_UNDERSCORES
sein. Wenn Sie Enum-Werte als Funktionsargumente übergeben und als Funktionsrückgaben zurückgeben, verwenden Sie den tatsächlichen Enum-Typ (nicht den zugrunde liegenden Integer-Typ). 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 Enum-Typs übersichtlicher.
Bei vollqualifizierten Namen für Enum-Werte wird ein Doppelpunkt zwischen dem Namen des Enum-Typs und dem Namen des Enum-Werts verwendet:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
Innerhalb eines vollständig qualifizierten Namens dürfen keine Leerzeichen enthalten sein. 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. Obwohl HIDL//
für Kommentare unterstützt, wird davon abgeraten, da sie nicht in der generierten Ausgabe erscheinen. - Verwenden Sie
/** */
für generierte Dokumentation. Diese können nur auf Typ-, Methoden-, Feld- und Aufzählungswertdeklarationen 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: * ... */
Kommentare ablegen
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
. Denken Sie daran, das Jahr zu aktualisieren und mehrzeilige Kommentare im Stil von /* */
wie oben beschrieben zu verwenden.
Optional können Sie nach dem Lizenzhinweis eine Leerzeile einfügen, gefolgt von einer Änderungsprotokoll-/Versionsinformation. Verwenden Sie mehrzeilige Kommentare im Stil von /* */
wie oben erläutert, platzieren Sie die leere Zeile nach dem Änderungsprotokoll und folgen Sie dann 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 erlaubt; 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.
Docstrings für Schnittstellen sollten allgemeine Mechanismen der Schnittstelle, Designgründe, Zweck usw. beschreiben. Docstrings für Funktionen sollten funktionsspezifisch 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 der Docstring folgen. -
@return
muss für jeden Rückgabewert hinzugefügt werden. Darauf sollte der Name des Rückgabewerts und dann der Docstring 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:
- Zeilenlänge . Jede Textzeile sollte höchstens 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
- Verspannung . Mit Ausnahme von Anmerkungswerten steht eine öffnende geschweifte Klammer in derselben Zeile wie der vorhergehende Code, aber eine schließende geschweifte Klammer und das folgende Semikolon nehmen die gesamte Zeile ein. Beispiel:
interface INfc { close(); };
Paketerklärung
Die Paketdeklaration sollte am Anfang der Datei nach dem Lizenzhinweis stehen, die gesamte Zeile einnehmen und nicht eingerückt sein. Pakete werden unter Verwendung des folgenden Formats deklariert (zur Namensformatierung siehe 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 die gleiche Zeile passen, versuchen Sie, Parameter und Rückgabewerte auf die gleiche Einrückungsebene zu setzen 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 der gleichen Zeile wie der Funktionsname.
- Keine Leerzeichen zwischen dem Funktionsnamen und der öffnenden Klammer.
- Keine Leerzeichen zwischen den Klammern und Parametern, außer wenn Zeilenumbrüche dazwischen stehen.
- Befindet sich
generates
in derselben Zeile wie die vorherige schließende Klammer, verwenden Sie ein vorangestelltes Leerzeichen. Befindet sichgenerates
“ in derselben Zeile wie die nächste offene Klammer, folgt ein Leerzeichen. - Gleichen Sie alle Parameter und Rückgabewerte (wenn möglich) an.
- Der Standardeinzug beträgt 4 Leerzeichen.
- Umbrochene Parameter werden an den ersten Parametern in der vorherigen Zeile ausgerichtet, andernfalls haben sie einen Einzug von 8 Leerzeichen.
Anmerkungen
Verwenden Sie das folgende Format für Anmerkungen:
@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 um 8 Leerzeichen ein. Beispiel:
@annotate( keyword = value, keyword = { value, value }, keyword = value)
Wenn das gesamte Wertarray nicht in dieselbe Zeile passt, setzen Sie Zeilenumbrüche nach offenen Klammern {
und nach jedem Komma innerhalb des Arrays. Platzieren Sie die schließende Klammer unmittelbar nach dem letzten Wert. Setzen Sie die geschweiften Klammern nicht, wenn es nur einen Wert gibt.
Wenn das gesamte Wertarray in dieselbe Zeile passt, verwenden Sie keine Leerzeichen nach öffnenden und vor schließenden Klammern und verwenden Sie ein Leerzeichen nach jedem Komma. Beispiele:
/* Good */ @callflow(key = {"val", "val"}) /* Bad */ @callflow(key = { "val","val" })
Zwischen Annotationen 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 Aufzählungswert kann ein zusätzliches Komma haben oder nicht.
Strukturdeklarationen
Verwenden Sie die folgenden Regeln für Struct-Deklarationen:
- 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 vor der öffnenden geschweiften Klammer ein Leerzeichen.
- Feldnamen ausrichten (optional). Beispiel:
struct MyStruct { vec<uint8_t> data; int32_t someInt; }
Array-Deklarationen
Setzen Sie keine Leerzeichen zwischen:
- Elementtyp und offene eckige Klammer.
- Öffnen Sie die eckige Klammer und die Array-Größe.
- Array-Größe und schließende eckige Klammer.
- Schließen Sie die eckige Klammer und die nächste offene 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 keine Leerzeichen zwischen:
-
vec
und offene spitze Klammer. - Öffnen Sie spitze Klammer und 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;