Code-Styleguide

Der HIDL-Codestil ähnelt dem C++-Code im Android-Framework. Er hat vier Leerzeichen Einzüge und Dateinamen mit 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 HIDL-Code-Stile veranschaulichen und Quick Links zu Details zu jedem Stil bereitstellen (IFooClientCallback.hal, IBar.hal und IBaz.hal wurden ausgelassen.

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

Namenskonventionen

Funktions-, Variablen- und Dateinamen sollten beschreibend sein. vermeiden zu viele Abkürzungen. Akronyme wie Wörter behandeln (z. B. INfc verwenden) von INFC).

Verzeichnisstruktur und Dateibenennung

Die Verzeichnisstruktur sollte wie folgt aussehen:

  • ROOT-DIRECTORY
    • MODULE
      • SUBMODULE (optional, mehr als eins möglich) Level)
        • VERSION
          • Android.mk
          • IINTERFACE_1.hal
          • IINTERFACE_2.hal
          • IINTERFACE_N.hal
          • types.hal (optional)

Dabei gilt:

  • ROOT-DIRECTORY ist:
    • hardware/interfaces für HIDL-Kernpakete.
    • vendor/VENDOR/interfaces für Anbieterpakete, Dabei bezieht sich VENDOR auf einen SoC-Anbieter oder einen OEM/ODM
  • MODULE muss ein kleingeschriebenes Wort sein, das folgendes beschreibt: des Subsystems (z. B. nfc). Wenn mehr als ein Wort erforderlich ist, verwenden Sie verschachtelte SUBMODULE. Es können mehrere Ebenen von Verschachtelung.
  • VERSION sollte genau die gleiche Version sein (major.minor) wie unter Versionen beschrieben.
  • IINTERFACE_X sollte der Name der Schnittstelle mit UpperCamelCase/PascalCase (z. B. INfc) enthalten, wie unter Schnittstellennamen beschrieben.

Beispiel:

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

Hinweis:Alle Dateien müssen nicht ausführbare Dateien haben. Berechtigungen (in Git).

Paketnamen

Paketnamen müssen den folgenden vollständig qualifizierten Namen verwenden: (FQN) (bezeichnet als PACKAGE-NAME):

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

Dabei gilt:

  • PACKAGE ist das Paket, das der ROOT-DIRECTORY. Insbesondere PACKAGE ist:
    • android.hardware für Kern-HIDL-Pakete (Zuordnung zu hardware/interfaces).
    • vendor.VENDOR.hardware für Anbieterpakete, wobei VENDOR bezieht sich auf einen SoC-Anbieter oder einen OEM/ODM (Zuordnungs- an vendor/VENDOR/interfaces).
  • MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION Ordnernamen in der unter Verzeichnisstruktur.
  • Paketnamen sollten in Kleinbuchstaben geschrieben werden. Wenn sie aus mehr als einem Wort bestehen, Wörter sollten entweder als untergeordnete Module verwendet oder in snake_case geschrieben werden.
  • Leerzeichen sind nicht zulässig.

Die FQN wird immer in Paketdeklarationen verwendet.

Versionen

Versionen sollten das folgende Format haben:

MAJOR.MINOR

Sowohl die Version MAJOR als auch die Version MINOR sollten eine einzelne Version sein. Integer HIDL verwendet semantische Versionsverwaltungsregeln.

Importe

Importe haben eines der folgenden drei Formate:

  • Gesamtpaketimporte: import PACKAGE-NAME;
  • Teilimporte: import PACKAGE-NAME::UDT; (oder, wenn die importierten Typ befindet sich im selben Paket,import UDT;
  • Nur-Typen-Importe: import PACKAGE-NAME::types;

PACKAGE-NAME hat folgendes Format: Paketnamen: Das aktuelle Paket types.hal (falls vorhanden) wird automatisch importiert (nicht importieren) explizit).

Voll qualifizierte Namen (Fully Qualified Names, FQNs)

Verwenden Sie für einen Import benutzerdefinierter Typen nur dann voll qualifizierte Namen, wenn dies erforderlich ist. Lassen Sie PACKAGE-NAME aus, wenn der Importtyp im selben Paket. Eine Voll qualifizierter Name (FQN) darf keine Leerzeichen enthalten. Beispiel für einen voll qualifizierten Namen:

android.hardware.nfc@1.0::INfcClientCallback

In einer anderen Datei unter android.hardware.nfc@1.0 finden Sie weitere Informationen im oben als INfcClientCallback angezeigt. Andernfalls verwenden Sie nur das Feld vollständig qualifizierter Name.

Importe gruppieren und sortieren

Fügen Sie nach der Paketdeklaration (vor den Importen) eine leere Zeile ein. Jeder Import sollte eine einzelne Zeile belegen und nicht eingerückt sein. Gruppenimporte in der folgende Reihenfolge:

  1. Andere android.hardware-Pakete (voll qualifizierte Namen verwenden)
  2. Andere vendor.VENDOR-Pakete (vollständig qualifiziertes Paket verwenden) Namen).
    • Bei jedem Anbieter sollte es sich um eine Gruppe handeln.
    • Sortieren Sie die Anbieter alphabetisch.
  3. Importiert aus anderen Schnittstellen im selben Paket (einfache Namen verwenden).

Verwenden Sie eine leere Zeile zwischen den Gruppen. Importe in jeder Gruppe sortieren alphabetisch sortiert. 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 Name. Eine Schnittstelle mit Namen IFoo muss in der Datei IFoo.hal definiert sein. Diese Datei kann nur Definitionen für die IFoo-Schnittstelle (die Schnittstelle) enthalten. INAME sollte in INAME.hal sein.

Funktionen

Für Funktionsnamen, Argumente und Rückgabevariablennamen verwenden Sie lowerCamelCase Beispiel:

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

Namen von Struct- und Union-Feldern

Verwenden Sie für Struct- oder Union-Feldnamen lowerCamelCase. Beispiel:

struct FooReply {
    vec<uint8_t> replyData;
}

Typnamen

Typnamen beziehen sich auf Struktur- oder Union-Definitionen, Enum-Typdefinitionen typedef Sek. 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. Beim Bestehen enum-Werte als Funktionsargumente zu ermitteln und als Funktionsrückgaben zurückzugeben, den tatsächlichen enum-Typ (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 einem Enum-Typ zugrunde liegende Typ ist explizit nach dem Doppelpunkt angegeben wird. Da die Anwendung nicht Compiler-abhängig ist, verwenden Sie ist der tatsächliche enum-Typ klarer.

Für voll qualifizierte Namen für enum-Werte wird ein Doppelpunkt verwendet. zwischen dem Namen des Enum-Typs und dem Namen des enum-Werts:

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

Vollständig qualifizierte Namen dürfen keine Leerzeichen enthalten. Verwenden Sie eine voll qualifizierte und lassen Sie unnötige Teile weg. Beispiel:

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

Kommentare

Für einen einzeiligen Kommentar: //, /* */ und /** */ sind in Ordnung.

// This is a single line comment
/* This is also single line comment */
/** This is documentation comment */
  • /* */ für Kommentare verwenden. HIDL unterstützt zwar // für Kommentare, da sie in der generierten Ausgabe nicht enthalten sind.
  • Verwenden Sie /** */ für die generierte Dokumentation. Diese können angewendet werden, nur für Typ-, Methode-, Feld- und ENUM-Wertdeklarationen. 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. Verwende * am Anfang jeder Zeile. Schließen Sie den Kommentar mit */ in einer separaten Zeile ab und richten Sie dabei die Sternchen aus. Beispiel:
    /**
     * My multi-line
     * comment
     */
    
  • Im Lizenzierungshinweis und in Änderungsprotokollen sollte eine neue Zeile mit „/*“ beginnen (ein einzelnes Sternchen), verwenden Sie * am Anfang jeder Zeile und setzen Sie */ in der letzten Zeile für sich alleine (Sternchen sollten übereinstimmen). Beispiel:
    /*
     * Copyright (C) 2017 The Android Open Source Project
     * ...
     */
    
    /*
     * Changelog:
     * ...
     */
    

Dateikommentare

Beginnen Sie jede Datei mit dem entsprechenden Lizenzhinweis. Für Kern-HALs die AOSP Apache-Lizenz in development/docs/copyright-templates/c.txt Vergiss nicht, das Jahr zu aktualisieren und mehrzeilige /* */ Kommentare im Stil von mehrzeiligen Kommentaren zu verwenden. wie oben beschrieben.

Optional kannst du nach dem Lizenzhinweis eine leere Zeile einfügen, gefolgt von Änderungsprotokoll/Versionierungsinformationen. /* */-Stil verwenden mehrzeiligen Kommentaren wie oben erläutert, platzieren Sie die leere Zeile nach dem und folge dann der Paketdeklaration.

TODO-Kommentare

TODOs sollten den String TODO in Großbuchstaben enthalten, gefolgt von einem Doppelpunkt. Beispiel:

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

TODO-Kommentare sind nur während der Entwicklung erlaubt. sie müssen nicht in veröffentlichten Benutzeroberflächen vorhanden.

Kommentare zur Benutzeroberfläche und zu Funktionen (Docstrings)

Verwenden Sie /** */ für mehrzeilige und einzeilige Dokumentstrings. Nicht verwenden // für docstrings.

In Docstrings für Schnittstellen sollten allgemeine Mechanismen der Benutzeroberfläche, Designgrundsätze, Zweck usw. Docstrings für Funktionen sollten speziell für die Funktion (Dokumentation auf Paketebene befindet sich in einer README-Datei in 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();
};

Du musst jeweils @param- und @return-Werte hinzufügen. Parameter/Rückgabewert:

  • Für jeden Parameter muss @param hinzugefügt werden. Es sollte gefolgt vom Namen des Parameters und dann dem docstring.
  • Für jeden Rückgabewert muss @return hinzugefügt werden. Es muss 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);

Regeln formatieren

Zu den allgemeinen Formatierungsregeln gehören:

  • Zeilenlänge: Jede Textzeile sollte höchstens 100 Spalten lang.
  • Leerräume: Keine Leerzeichen am Ende der Zeilen Leere Zeilen darf keine Leerzeichen enthalten.
  • Gruppenbereiche und Tabs im Vergleich Verwenden Sie nur Leerzeichen.
  • Einzugsgröße: Verwenden Sie 4 Leerzeichen für Blöcke und 8 Leerzeichen für Zeilenumbruch
  • Verband: Mit Ausnahme von Anmerkungen Werte steht, steht eine offene geschweifte Klammer in dieselbe Zeile wie die vorherige sondern mit einer schließenden geschweiften Klammer und dem folgenden Semikolon die gesamte Linie. Beispiel:
    interface INfc {
        close();
    };
    

Paketdeklaration

Die Paketdeklaration muss sich nach der Lizenz oben in der Datei befinden die gesamte Zeile einnehmen und nicht eingerückt werden darf. Pakete sind im folgenden Format deklariert (Informationen zur Namensformatierung siehe Paketnamen):

package PACKAGE-NAME;

Beispiel:

package android.hardware.nfc@1.0;

Funktionsdeklarationen

Funktionsname, Parameter, generates und Rückgabewerte sollten auf derselben Linie 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 einzufügen und derselben Einrückung gegliedert sind und generate voneinander abgrenzen, können die Lesenden die Parameter und Rückgabewerte schnell sehen. 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 Informationen:

  • Eine offene Klammer steht immer in derselben Zeile wie der Funktionsname.
  • Keine Leerzeichen zwischen dem Funktionsnamen und der öffnenden Klammer.
  • Keine Leerzeichen zwischen Klammern und Parametern, es sei denn, sind Zeilenumbrüche dazwischen.
  • Wenn sich generates in derselben Zeile wie die vorherige schließende Klammer ein und verwenden Sie ein vorangestelltes Leerzeichen. Wenn generates auf demselben als nächste öffnende Klammer ein, gefolgt von einem Leerzeichen.
  • Richten Sie alle Parameter aus und geben Sie Werte zurück (falls möglich).
  • Der Standardeinzug beträgt 4 Leerzeichen.
  • Umgebrochene Parameter werden an den ersten Parametern der vorherigen Zeile Andernfalls haben sie einen Einzug 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

Eine Anmerkung muss die gesamte Zeile ausfüllen. Beispiele:

/* Good */
@entry
@exit

/* Bad */
@entry @exit

Wenn die Anmerkungen nicht in dieselbe Zeile passen, rücken Sie sie mit acht Leerzeichen ein. Beispiel:

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

Wenn nicht das gesamte Wertearray in dieselbe Zeile passt, setzen Sie Zeilenumbrüche nach { und nach jedem Komma im Array müssen geschweifte Klammern angegeben werden. Ort wird geschlossen direkt nach dem letzten Wert ein. Setzen Sie die Klammern nicht, wenn nur einen Wert.

Wenn das gesamte Werte-Array in dieselbe Zeile passen kann, verwenden Sie nach dem Absatz keine Leerzeichen. vor und nach schließenden Klammern. Verwenden Sie nach jedem Komma ein Leerzeichen. Beispiele:

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

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

Zwischen Anmerkungen und der Funktion dürfen KEINE leeren Zeilen stehen Erklärung. Beispiele:

/* Good */
@entry
foo();

/* Bad */
@entry

foo();

Enum-Deklarationen

Verwenden Sie für enum-Deklarationen die folgenden Regeln:

  • Wenn enum-Deklarationen für ein anderes Paket freigegeben werden, platzieren Sie die Deklarationen in types.hal, anstatt sie in eine Schnittstelle einzubetten.
  • Verwenden Sie vor und nach dem Doppelpunkt ein Leerzeichen und nach dem zugrunde liegenden Typ ein Leerzeichen. vor die öffnende geschweifte Klammer.
  • Der letzte enum-Wert darf kein zusätzliches Komma enthalten.

Strukturdeklarationen

Verwenden Sie für Strukturdeklarationen die folgenden Regeln:

  • Wenn Struct-Deklarationen mit einem anderen Paket geteilt werden, platziere die Deklarationen in types.hal, anstatt sie in eine Schnittstelle einzubetten.
  • Fügen Sie nach dem Namen des Strukturtyps ein Leerzeichen vor der öffnenden geschweiften Klammer ein.
  • Feldnamen ausrichten (optional). Beispiel:
    struct MyStruct {
        vec<uint8_t>   data;
        int32_t        someInt;
    }
    

Array-Deklarationen

Fügen Sie keine Leerzeichen zwischen den folgenden Elementen ein:

  • Elementtyp und offene eckige Klammer.
  • Offene eckige Klammer und Arraygröße.
  • Arraygröße und schließende eckige Klammer.
  • Eckige Klammer und die nächste offene eckige Klammer schließen (falls mehrere vorhanden) Dimension existiert.

Beispiele:

/* Good */
int32_t[5] array;

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

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

Vektoren

Fügen Sie keine Leerzeichen zwischen den folgenden Elementen ein:

  • vec und spitze Klammer auf.
  • Öffnende spitze Klammer und Elementtyp (Ausnahme: Der Elementtyp ist ebenfalls ein vec.
  • Elementtyp und schließende spitze Klammer (Ausnahme: Der Elementtyp ist ebenfalls 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;