Kod stili kılavuzu

HIDL kod stili, Android çerçevesindeki C++ koduna benzer. 4 boşluklu girintiler ve karma harfli dosya adları kullanılır. Paket bildirimleri, içe aktarmalar ve doküman dizeleri Java'dakilere benzer ancak küçük değişiklikler içerir.

IFoo.hal ve types.hal ile ilgili aşağıdaki örnekler, HIDL kodu stillerini gösterir ve her stille ilgili ayrıntılara hızlı bağlantılar sağlar (IFooClientCallback.hal, IBar.hal ve IBaz.hal atlanmıştır).

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

Adlandırma kuralları

İşlev adları, değişken adları ve dosya adları açıklayıcı olmalıdır. Aşırı kısaltma yapmayın. Kısaltmaları kelime olarak değerlendirin (örneğin, INFC yerine INfc kullanın).

Dizin yapısı ve dosya adlandırma

Dizin yapısı aşağıdaki gibi görünmelidir:

  • ROOT-DIRECTORY
    • MODULE
      • SUBMODULE (isteğe bağlı, birden fazla düzey olabilir)
        • VERSION
          • Android.mk
          • IINTERFACE_1.hal
          • IINTERFACE_2.hal
          • IINTERFACE_N.hal
          • types.hal (isteğe bağlı)

Nerede:

  • ROOT-DIRECTORY is:
    • Temel HIDL paketleri için hardware/interfaces.
    • vendor/VENDOR/interfaces satıcı paketleri için, burada VENDOR bir SoC satıcısını veya bir OEM/ODM'yi ifade eder.
  • MODULE, alt sistemi açıklayan küçük harfli tek bir kelime olmalıdır (örneğin, nfc). Birden fazla kelime gerekiyorsa iç içe SUBMODULE kullanın. Birden fazla iç içe yerleştirme düzeyi olabilir.
  • VERSION, Sürümler bölümünde açıklandığı gibi tam olarak aynı sürüm (ana.alt) olmalıdır.
  • IINTERFACE_X, Arayüz adları bölümünde açıklandığı gibi UpperCamelCase/PascalCase (ör. INfc) ile arayüz adı olmalıdır.

Örnek:

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

Not: Tüm dosyaların yürütülemeyen izinlere (Git'te) sahip olması gerekir.

Paket adları

Paket adları, aşağıdaki tam nitelikli ad (FQN) biçimini (PACKAGE-NAME olarak adlandırılır) kullanmalıdır:

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

Nerede:

  • PACKAGE, ROOT-DIRECTORY ile eşlenen pakettir. Özellikle, PACKAGE:
    • Temel HIDL paketleri için android.hardware (hardware/interfaces ile eşleme).
    • vendor.VENDOR.hardware satıcı paketleri için. Burada VENDOR, bir SoC satıcısını veya bir OEM/ODM'yi (vendor/VENDOR/interfaces ile eşleme) ifade eder.
  • MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION Dizin yapısı bölümünde açıklanan yapıda yer alan klasör adlarıyla aynıdır.
  • Paket adları küçük harf olmalıdır. Birden fazla kelimeden oluşuyorsa kelimeler alt modül olarak kullanılmalı veya snake_case içinde yazılmalıdır.
  • Boşluk kullanılamaz.

Paket bildirimlerinde her zaman FQN kullanılır.

Sürümler

Sürümler aşağıdaki biçimde olmalıdır:

MAJOR.MINOR

Hem MAJOR hem de MINOR sürümü tek bir tam sayı olmalıdır. HIDL, anlamsal sürüm oluşturma kurallarını kullanır.

İçe Aktarımlar

İçe aktarma işlemi aşağıdaki üç biçimden birinde olabilir:

  • Tam paket içe aktarma sayısı: import PACKAGE-NAME;
  • Kısmi içe aktarmalar: import PACKAGE-NAME::UDT; (veya içe aktarılan tür aynı paketteyse import UDT;
  • Yalnızca türlerin içe aktarıldığı durumlar: import PACKAGE-NAME::types;

PACKAGE-NAME, Paket adları bölümündeki biçime uygundur. Mevcut paketin types.hal (varsa) otomatik olarak içe aktarılır (açıkça içe aktarmayın).

Tam nitelikli adlar (FQNs)

Kullanıcı tanımlı tür içe aktarma için tam nitelikli adları yalnızca gerektiğinde kullanın. İçe aktarma türü aynı paketteyse PACKAGE-NAME öğesini atlayın. Tam ad boşluk içermemelidir. Tam nitelikli ad örneği:

android.hardware.nfc@1.0::INfcClientCallback

android.hardware.nfc@1.0 bölümündeki başka bir dosyada, yukarıdaki arayüzden INfcClientCallback olarak bahsedin. Aksi takdirde, yalnızca tam nitelikli adı kullanın.

İçe aktarma işlemlerini gruplandırma ve sıralama

Paket bildiriminden sonra (içe aktarmalardan önce) boş bir satır kullanın. Her içe aktarma işlemi tek bir satırda yer almalı ve girintili olmamalıdır. Aşağıdaki sırayla grup içe aktarma işlemleri:

  1. Diğer android.hardware paketleri (tam nitelikli adlar kullanın).
  2. Diğer vendor.VENDOR paketleri (tam nitelikli adlar kullanın).
    • Her satıcı bir grup olmalıdır.
    • Tedarikçileri alfabetik olarak sıralayın.
  3. Aynı paketteki diğer arayüzlerden yapılan içe aktarmalar (basit adlar kullanın).

Gruplar arasında boş bir satır kullanın. Her grubun içindeki içe aktarmaları alfabetik olarak sıralayın. Örnek:

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;

Arayüz adları

Arayüz adları I ile başlamalı, ardından UpperCamelCase/PascalCase adı gelmelidir. IFoo.hal dosyasında IFoo adlı bir arayüz tanımlanmalıdır. Bu dosya yalnızca IFoo arayüzü için tanımlar içerebilir (arayüz INAME, INAME.hal içinde olmalıdır).

İşlevler

İşlev adları, bağımsız değişkenler ve döndürülen değişken adları için lowerCamelCase kullanın. Örnek:

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

Yapı ve birleşim alanı adları

Yapı veya birleşim alanı adları için lowerCamelCase kullanın. Örnek:

struct FooReply {
    vec<uint8_t> replyData;
}

Tür adları

Tür adları, yapı veya birleşim tanımlarını, enum türü tanımlarını ve typedef'ları ifade eder. Bu adlar için UpperCamelCase/PascalCase kullanın. Örnekler:

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

Enum değerleri

Enum değerleri UPPER_CASE_WITH_UNDERSCORES olmalıdır. Numaralandırılmış değerleri işlev bağımsız değişkenleri olarak geçirirken ve işlev dönüşleri olarak döndürürken gerçek numaralandırılmış türü (temel alınan tam sayı türü değil) kullanın. Örnek:

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

Not: Enum türünün temel türü, iki nokta üst üste işaretinden sonra açıkça belirtilir. Derleyiciye bağlı olmadığından gerçek enum türünü kullanmak daha anlaşılırdır.

Numaralandırılmış değerlerin tam adları için numaralandırılmış tür adı ile numaralandırılmış değer adı arasında iki nokta üst üste kullanılır:

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

Tam nitelikli adın içinde boşluk olmamalıdır. Tam nitelikli bir adı yalnızca gerektiğinde kullanın ve gereksiz kısımları atlayın. Örnek:

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

Yorumlar

Tek satırlık yorum için //, /* */ ve /** */ uygundur.

// This is a single line comment
/* This is also single line comment */
/** This is documentation comment */
  • Yorumlar için /* */ kullanın. HIDL, yorumlar için //'ı desteklese de oluşturulan çıktıda görünmediğinden bu karakterin kullanılması önerilmez.
  • Oluşturulan dokümanlar için /** */ öğesini kullanın. Bunlar yalnızca tür, yöntem, alan ve enum değeri bildirimlerine uygulanabilir. Örnek:
    /** 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,
        ...
    }
  • Çok satırlı yorumları ayrı bir satırda /** ile başlatın. Her satırın başında * kullanın. Yorumu ayrı bir satırda, yıldız işaretlerini hizalayarak */ ile sonlandırın. Örnek:
    /**
     * My multi-line
     * comment
     */
  • Lisans bildirimi ve değişiklik günlükleri /* ile yeni bir satırda başlamalıdır (tek yıldız), her satırın başında * kullanılmalı ve son satıra */ tek başına yerleştirilmelidir (yıldızlar hizalanmalıdır). Örnek:
    /*
     * Copyright (C) 2017 The Android Open Source Project
     * ...
     */
    
    /*
     * Changelog:
     * ...
     */

Dosya yorumları

Her dosyaya uygun lisanslama bildirimiyle başlayın. Temel HAL'ler için bu, development/docs/copyright-templates/c.txt içindeki AOSP Apache lisansı olmalıdır. Yılı güncellemeyi ve yukarıda açıklandığı gibi /* */ stilinde çok satırlı yorumlar kullanmayı unutmayın.

İsteğe bağlı olarak lisans bildiriminden sonra boş bir satır ekleyebilir, ardından değişiklik günlüğü/sürüm oluşturma bilgileri ekleyebilirsiniz. Yukarıda açıklandığı gibi /* */ stilinde çok satırlı yorumlar kullanın, boş satırı değişiklik günlüğünden sonra yerleştirin ve ardından paket bildirimini ekleyin.

Yapılacaklar yorumları

Yapılacaklar listesi, tamamen büyük harflerle yazılmış TODO dizesini ve ardından iki nokta üst üste işaretini içermelidir. Örnek:

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

TODO yorumlarına yalnızca geliştirme sırasında izin verilir. Yayınlanan arayüzlerde bulunmamalıdır.

Arayüz ve işlev yorumları (docstring'ler)

Çok satırlı ve tek satırlı docstring'ler için /** */ kullanın. Docstring'lerde // kullanmayın.

Arayüzlerin doküman dizeleri, arayüzün genel mekanizmalarını, tasarım gerekçesini, amacını vb. açıklamalıdır. İşlevlerin doküman dizeleri işlevle ilgili olmalıdır (paket düzeyindeki dokümanlar, paket dizinindeki bir README dosyasına yerleştirilir).

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

Her parametre/dönüş değeri için @param ve @return eklemeniz gerekir:

  • Her parametre için @param eklenmelidir. Parametre adının ve ardından docstring'in gelmesi gerekir.
  • Her dönüş değeri için @return eklenmelidir. Dönüş değerinin adı ve ardından docstring gelmelidir.

Örnek:

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

Biçimlendirme kuralları

Genel biçimlendirme kuralları şunlardır:

  • Satır uzunluğu Her metin satırı en fazla 100 sütun uzunluğunda olmalıdır.
  • Boşluklar. Satırların sonunda boşluk olmamalıdır. Boş satırlar boşluk içermemelidir.
  • Boşluk ve sekme karşılaştırması. Yalnızca boşluk kullanın.
  • Girinti boyutu Bloklar için 4 boşluk, satır sarmaları için 8 boşluk kullanın.
  • Destekleme. Açıklama değerleri hariç olmak üzere, açık ayraçlar önceki kodla aynı satırda yer alır ancak kapalı ayraç ve sonraki noktalı virgül tüm satırı kaplar. Örnek:
    interface INfc {
        close();
    };

Paket beyanı

Paket bildirimi, lisans bildiriminden sonra dosyanın en üstünde yer almalı, satırın tamamını kaplamalı ve girintili olmamalıdır. Paketler aşağıdaki biçimde beyan edilir (ad biçimlendirmesi için Paket adları bölümüne bakın):

package PACKAGE-NAME;

Örnek:

package android.hardware.nfc@1.0;

İşlev beyanları

İşlev adı, parametreler, generates ve döndürülen değerler sığıyorsa aynı satırda olmalıdır. Örnek:

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

Aynı satıra sığmıyorlarsa parametreleri ve dönüş değerlerini aynı girinti düzeyine yerleştirmeye çalışın ve okuyucunun parametreleri ve dönüş değerlerini hızlıca görmesine yardımcı olmak için generate ile ayırın. Örnek:

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

Ek ayrıntılar:

  • Açık parantez her zaman işlev adıyla aynı satırda yer alır.
  • İşlev adı ile açma parantezi arasında boşluk olmamalıdır.
  • Parantezler ve parametreler arasında boşluk olmamalıdır ancak aralarında satır beslemeleri olduğunda boşluk olabilir.
  • generates önceki kapatma paranteziyle aynı satırda yer alıyorsa öncesinde boşluk kullanın. generates, sonraki açma paranteziyle aynı satırda yer alıyorsa boşluk bırakın.
  • Mümkünse tüm parametreleri ve dönüş değerlerini hizalayın.
  • Varsayılan girinti 4 boşluktur.
  • Sarmalanmış parametreler, önceki satırdaki ilk parametrelerle hizalanır. Aksi takdirde, 8 boşlukluk bir girintiye sahip olurlar.

Ek açıklamalar

Açıklamalar için aşağıdaki biçimi kullanın:

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

Ek açıklamaları alfabetik sıraya göre sıralayın ve eşittir işaretlerinin etrafında boşluk kullanın. Örnek:

@callflow(key = value)
@entry
@exit

Açıklamanın satırın tamamını kapladığından emin olun. Örnekler:

/* Good */
@entry
@exit

/* Bad */
@entry @exit

Açıklamalar aynı satıra sığmıyorsa 8 boşluk girintisi kullanın. Örnek:

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

Değer dizisinin tamamı aynı satıra sığmıyorsa açma ayraçlarından { ve dizinin içindeki her virgülden sonra satır sonu ekleyin. Kapatma parantezini son değerin hemen ardından yerleştirin. Yalnızca tek bir değer varsa küme parantezlerini kullanmayın.

Değer dizisinin tamamı aynı satıra sığıyorsa açma ayraçlarından sonra ve kapatma ayraçlarından önce boşluk kullanmayın ve her virgülden sonra bir boşluk kullanın. Örnekler:

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

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

Açıklamalar ile işlev bildirimi arasında boş satır olmamalıdır. Örnekler:

/* Good */
@entry
foo();

/* Bad */
@entry

foo();

Numaralandırılmış değer tanımlamaları

Numaralandırma bildirimleri için aşağıdaki kuralları kullanın:

  • Numara sabitleri bildirimleri başka bir paketle paylaşılıyorsa bildirimleri bir arayüze yerleştirmek yerine types.hal içine koyun.
  • İki nokta üst üste işaretinden önce ve sonra boşluk bırakın. Ayrıca, temel türden sonra ve küme parantezinden önce boşluk bırakın.
  • Son numaralandırma değerinde fazladan virgül olmayabilir.

Yapı beyanları

Yapı bildirimleri için aşağıdaki kuralları kullanın:

  • Yapı bildirimleri başka bir paketle paylaşılıyorsa bildirimleri bir arayüze yerleştirmek yerine types.hal içine koyun.
  • Açık ayraçtan önce yapı türü adından sonra boşluk kullanın.
  • Alan adlarını hizalayın (isteğe bağlı). Örnek:
    struct MyStruct {
        vec<uint8_t>   data;
        int32_t        someInt;
    }

Dizi bildirimleri

Aşağıdaki öğeler arasına boşluk bırakmayın:

  • Öğe türü ve açık köşeli parantez.
  • Açık köşeli parantez ve dizi boyutu.
  • Dizi boyutu ve kapatma köşeli parantezi.
  • Köşeli parantezi kapatın ve birden fazla boyut varsa bir sonraki açık köşeli parantezi kapatın.

Örnekler:

/* Good */
int32_t[5] array;

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

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

Vektörler

Aşağıdaki öğeler arasına boşluk bırakmayın:

  • vec ve sol açılı parantez.
  • Sol açılı parantez ve öğe türü (İstisna: öğe türü aynı zamanda a vec).
  • Öğe türü ve kapatma açılı ayraç (İstisna: Öğe türü de bir vec).

Örnekler:

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