Panduan gaya kode

Gaya kode HIDL menyerupai kode C++ dalam framework Android, dengan 4 spasi {i>indent<i} dan nama {i>file<i} huruf besar/kecil. Deklarasi, impor, dan docstring paket mirip dengan yang ada di Java, dengan sedikit modifikasi.

Contoh berikut untuk IFoo.hal dan types.hal mengilustrasikan gaya kode HIDL dan menyediakan tautan cepat ke detail pada setiap gaya (IFooClientCallback.hal, IBar.hal, dan IBaz.hal telah dihilangkan).

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

Konvensi penamaan

Nama fungsi, nama variabel, dan nama file harus deskriptif; hindari singkatan yang berlebihan. Perlakukan akronim sebagai kata (misalnya, gunakan INfc sebagai gantinya dari INFC).

Struktur direktori dan penamaan file

Struktur direktori akan terlihat seperti berikut:

  • ROOT-DIRECTORY
    • MODULE
      • SUBMODULE (opsional, dapat lebih dari satu tingkat)
        • VERSION
          • Android.mk
          • IINTERFACE_1.hal
          • IINTERFACE_2.hal
          • IINTERFACE_N.hal
          • types.hal (opsional)

Dalam hal ini:

  • ROOT-DIRECTORY adalah:
    • hardware/interfaces untuk paket HIDL inti.
    • vendor/VENDOR/interfaces untuk paket vendor, dengan VENDOR mengacu pada vendor SoC atau OEM/ODM.
  • MODULE harus berupa satu kata huruf kecil yang mendeskripsikan subsistem (misalnya, nfc). Jika diperlukan lebih dari satu kata, gunakan SUBMODULE bertingkat. Bisa terdapat lebih dari satu tingkat secara bertingkat.
  • VERSION harus sama persis dengan versi (major.minor) seperti yang dijelaskan di Versi.
  • IINTERFACE_X harus berupa nama antarmuka dengan UpperCamelCase/PascalCase (misalnya, INfc) seperti yang dijelaskan dalam Nama antarmuka.

Contoh:

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

Catatan: Semua file harus memiliki file yang tidak dapat dieksekusi izin (di Git).

Nama paket

Nama paket harus menggunakan nama yang sepenuhnya memenuhi syarat berikut ini (FQN) (disebut sebagai PACKAGE-NAME):

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

Dalam hal ini:

  • PACKAGE adalah paket yang dipetakan ke ROOT-DIRECTORY. Secara khusus, kita akan membuat PACKAGE adalah:
    • android.hardware untuk paket HIDL inti (pemetaan ke hardware/interfaces).
    • vendor.VENDOR.hardware untuk paket vendor, dengan VENDOR mengacu pada vendor SoC atau OEM/ODM (pemetaan ke vendor/VENDOR/interfaces).
  • MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION adalah nama folder yang sama persis dalam struktur yang dijelaskan di Struktur direktori.
  • Nama paket harus huruf kecil. Jika panjangnya lebih dari satu kata, kata harus digunakan sebagai submodul atau ditulis dalam snake_case.
  • Tidak boleh ada spasi.

FQN selalu digunakan dalam deklarasi paket.

Versi

Versi harus memiliki format berikut:

MAJOR.MINOR

Baik versi MAJOR maupun MINOR harus berupa satu bilangan bulat. HIDL menggunakan semantik pembuatan versi baru.

Import

Impor memiliki salah satu dari tiga format berikut:

  • Impor paket utuh: import PACKAGE-NAME;
  • Impor sebagian: import PACKAGE-NAME::UDT; (atau, jika diimpor jenisnya dalam paket yang sama,import UDT;
  • Impor khusus jenis: import PACKAGE-NAME::types;

PACKAGE-NAME mengikuti format di Nama paket. Opsi paket saat ini types.hal (jika ada) diimpor secara otomatis (jangan impor secara eksplisit).

Nama yang sepenuhnya memenuhi syarat (FQN)

Gunakan nama yang sepenuhnya memenuhi syarat untuk impor jenis yang ditentukan pengguna hanya jika diperlukan. Hapus PACKAGE-NAME jika jenis impornya sama paket. FQN tidak boleh berisi spasi. Contoh nama yang sepenuhnya memenuhi syarat:

android.hardware.nfc@1.0::INfcClientCallback

Di file lain pada android.hardware.nfc@1.0, lihat di atas antarmuka sebagai INfcClientCallback. Jika tidak, hanya gunakan nama yang sepenuhnya memenuhi syarat.

Mengelompokkan dan mengurutkan impor

Gunakan baris kosong setelah deklarasi paket (sebelum impor). Setiap impor harus menempati satu baris dan tidak boleh diindentasi. Impor grup di urutan berikut:

  1. Paket android.hardware lainnya (gunakan nama yang sepenuhnya memenuhi syarat).
  2. Paket vendor.VENDOR lainnya (gunakan sepenuhnya memenuhi syarat nama).
    • Setiap vendor harus berupa grup.
    • Pesan vendor menurut abjad.
  3. Mengimpor dari antarmuka lain dalam paket yang sama (gunakan nama sederhana).

Gunakan baris kosong antar-grup. Di dalam setiap grup, urutkan impor menurut abjad. Contoh:

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;

Nama antarmuka

Nama antarmuka harus diawali dengan I, diikuti dengan Nama UpperCamelCase/PascalCase. Antarmuka dengan nama IFoo harus ditetapkan di file IFoo.hal. File ini hanya dapat berisi definisi untuk antarmuka IFoo (antarmuka INAME harus dalam INAME.hal ).

Fungsi

Untuk nama fungsi, argumen, dan nama variabel yang ditampilkan, gunakan lowerCamelCase. Contoh:

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

Nama kolom gabungan dan struktur

Untuk nama kolom union atau struktur, gunakan lowerCamelCase. Contoh:

struct FooReply {
    vec<uint8_t> replyData;
}

Nama jenis

Nama tipe mengacu pada definisi struct atau union, definisi tipe enum, dan typedef dtk. Untuk nama ini, gunakan UpperCamelCase/PascalCase. Contoh:

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

Nilai enum

Nilai enum harus UPPER_CASE_WITH_UNDERSCORES. Saat melewati nilai enum sebagai argumen fungsi dan menampilkannya saat fungsi kembali, gunakan jenis enum yang sebenarnya (bukan jenis bilangan bulat yang mendasarinya). Contoh:

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

Catatan: Jenis dasar dari jenis enum adalah yang dideklarasikan secara eksplisit setelah tanda titik dua. Karena tidak bergantung pada compiler, penggunaan jenis enum yang sebenarnya menjadi lebih jelas.

Guna mengetahui nama yang sepenuhnya memenuhi syarat untuk nilai enum, titik dua digunakan antara nama jenis enum dan nama nilai enum:

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

Tidak boleh ada spasi di dalam nama yang sepenuhnya memenuhi syarat. Gunakan nama hanya jika diperlukan dan hilangkan bagian yang tidak diperlukan. Contoh:

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

Komentar

Untuk komentar satu baris, //, /* */, dan /** */ baik-baik saja.

// This is a single line comment
/* This is also single line comment */
/** This is documentation comment */
  • Gunakan /* */ untuk komentar. Meskipun HIDL mendukung // untuk komentar, mereka tidak disarankan karena tidak muncul dalam {i>output<i} yang dihasilkan.
  • Gunakan /** */ untuk dokumentasi yang dihasilkan. Hal ini dapat diterapkan hanya untuk deklarasi nilai jenis, metode, kolom, dan enum. Contoh:
    /** 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,
        ...
    }
    
  • Mulai komentar multi-baris dengan /** pada baris terpisah. Gunakan * di awal setiap baris. Akhiri komentar dengan */ pada baris terpisah, sejajarkan tanda bintang. Contoh:
    /**
     * My multi-line
     * comment
     */
    
  • Pemberitahuan pemberian lisensi dan log perubahan harus memulai baris baru dengan /* (satu tanda bintang), gunakan * di awal setiap baris, dan tempatkan */ di baris terakhir semuanya sendiri (tanda bintang harus sejajar). Contoh:
    /*
     * Copyright (C) 2017 The Android Open Source Project
     * ...
     */
    
    /*
     * Changelog:
     * ...
     */
    

Komentar file

Mulai setiap file dengan pemberitahuan pemberian lisensi yang sesuai. Untuk HAL inti, harusnya lisensi AOSP Apache di development/docs/copyright-templates/c.txt Jangan lupa memperbarui tahun dan menggunakan komentar multibaris gaya /* */ sebagaimana dijelaskan di atas.

Anda juga dapat menempatkan baris kosong setelah pemberitahuan lisensi, yang diikuti oleh informasi {i>changelog<i}/pembuatan versi. Gunakan gaya /* */ komentar multi-baris seperti yang dijelaskan di atas, tempatkan baris kosong setelah {i>changelog<i}, lalu ikuti dengan deklarasi paket.

Komentar TODO

TODO harus menyertakan string TODO dalam huruf besar semua diikuti oleh titik dua. Contoh:

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

Komentar TODO hanya diizinkan selama pengembangan; mereka harus tidak ada dalam antarmuka yang diterbitkan.

Komentar antarmuka dan fungsi (docstring)

Gunakan /** */ untuk docstring multibaris dan satu baris. Jangan gunakan // untuk docstring.

Docstring untuk antarmuka harus menjelaskan mekanisme umum antarmuka, alasan desain, tujuan, dll. {i>Docstring<i} untuk fungsi harus khusus untuk fungsi tersebut (dokumentasi tingkat paket dimasukkan dalam file README di direktori paket).

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

Anda harus menambahkan @param dan @return untuk setiap parameter/nilai yang ditampilkan:

  • @param harus ditambahkan untuk setiap parameter. Seharusnya diikuti dengan nama parameter kemudian {i>docstring<i}.
  • @return harus ditambahkan untuk setiap nilai yang ditampilkan. Ini harus diikuti dengan nama nilai yang dikembalikan kemudian {i>docstring<i}.

Contoh:

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

Aturan pemformatan

Aturan pemformatan umum mencakup:

  • Panjang garis. Setiap baris teks maksimal harus 100 kolom.
  • Spasi kosong. Tidak ada spasi kosong di akhir baris; baris kosong tidak boleh berisi spasi kosong.
  • Ruang vs. tab. Hanya gunakan spasi.
  • Ukuran indentasi. Gunakan 4 spasi untuk blok dan 8 spasi untuk penggabungan baris
  • Penyangga. Kecuali anotasi nilai, kurung kurawal terbuka akan berada di baris yang sama dengan kode, tetapi tanda kurung kurawal tutup dan titik koma berikut menempati seluruh baris. Contoh:
    interface INfc {
        close();
    };
    

Pernyataan paket

Deklarasi paket harus berada di bagian atas file setelah lisensi perhatikan, harus menempati seluruh baris, dan tidak boleh diindentasi. Paket dideklarasikan menggunakan format berikut (untuk pemformatan nama, lihat Nama paket):

package PACKAGE-NAME;

Contoh:

package android.hardware.nfc@1.0;

Deklarasi fungsi

Nama fungsi, parameter, generates, dan nilai yang ditampilkan harus berada di garis yang sama jika mereka sesuai. Contoh:

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

Jika mereka tidak muat di baris yang sama, coba letakkan parameter dan tampilkan nilai dalam tingkat indentasi yang sama dan membedakan generate untuk membantu pembaca dengan cepat melihat parameter dan mengembalikan nilai. Contoh:

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

Detail tambahan:

  • Tanda kurung buka selalu berada di baris yang sama dengan nama fungsi.
  • Tidak ada spasi di antara nama fungsi dan tanda kurung buka.
  • Tidak ada spasi di antara tanda kurung dan parameter, kecuali jika ada adalah {i>line feed<i} di antara keduanya.
  • Jika generates berada di baris yang sama dengan penutup sebelumnya tanda kurung, gunakan spasi sebelumnya. Jika generates berada di lokasi yang sama sebagai tanda kurung buka berikutnya, diikuti dengan spasi.
  • Sejajarkan semua parameter dan tampilkan nilai (jika memungkinkan).
  • Indentasi default adalah 4 spasi.
  • Parameter yang digabungkan selaras dengan parameter pertama pada baris sebelumnya, jika tidak, mereka memiliki indentasi 8-spasi.

Anotasi

Gunakan format berikut untuk anotasi:

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

Urutkan anotasi dalam urutan abjad, dan gunakan spasi di sekitar tanda sama dengan. Contoh:

@callflow(key = value)
@entry
@exit

Memastikan anotasi memenuhi seluruh baris. Contoh:

/* Good */
@entry
@exit

/* Bad */
@entry @exit

Jika anotasi tidak dapat dimuat dalam baris yang sama, indentasi dengan 8 spasi. Contoh:

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

Jika seluruh larik nilai tidak bisa dimuat di baris yang sama, letakkan jeda baris setelah buka kurung kurawal { dan setelah setiap koma di dalam array. Tutup tempat dan tanda kurung tepat setelah nilai terakhir. Jangan letakkan kurung kurawal jika ada hanya dengan satu nilai.

Jika seluruh larik nilai bisa masuk ke dalam baris yang sama, jangan gunakan spasi setelahnya buka tanda kurung kurawal sebelum menutup dan gunakan satu spasi setelah setiap koma. Contoh:

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

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

TIDAK boleh ada baris kosong antara anotasi dan fungsi deklarasi. Contoh:

/* Good */
@entry
foo();

/* Bad */
@entry

foo();

Deklarasi enum

Gunakan aturan berikut untuk deklarasi enum:

  • Jika deklarasi enum dibagikan dengan paket lain, tempatkan deklarasi di types.hal, bukan menyematkannya di dalam antarmuka.
  • Gunakan spasi sebelum dan setelah titik dua, serta spasi setelah jenis pokok sebelum tanda kurung besar terbuka.
  • Nilai enum terakhir mungkin tidak memiliki koma tambahan.

Membuat deklarasi struktur

Gunakan aturan berikut untuk deklarasi struct:

  • Jika deklarasi struct dibagikan dengan paket lain, tempatkan deklarasi di types.hal, bukan menyematkannya di dalam antarmuka.
  • Gunakan spasi setelah nama jenis struct sebelum tanda kurung buka.
  • Sejajarkan nama kolom (opsional). Contoh:
    struct MyStruct {
        vec<uint8_t>   data;
        int32_t        someInt;
    }
    

Deklarasi array

Jangan letakkan spasi di antara yang berikut:

  • Jenis elemen dan kurung siku terbuka.
  • Tanda kurung siku buka dan ukuran array.
  • Ukuran array dan tutup kurung siku.
  • Tanda kurung siku tutup dan tanda kurung siku buka berikutnya, jika lebih dari satu dimensi kustom.

Contoh:

/* Good */
int32_t[5] array;

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

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

Vektor (Vectors)

Jangan letakkan spasi di antara yang berikut:

  • vec dan kurung sudut buka.
  • Tanda kurung sudut buka dan jenis elemen (Pengecualian: jenis elemen juga merupakan vec).
  • Jenis elemen dan kurung sudut tutup (Pengecualian: jenis elemen juga merupakan vec).

Contoh:

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