代碼風格指南

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

HIDL 代碼樣式類似於 Android 框架中的 C++ 代碼,具有 4 個空格縮進和混合大小寫的文件名。包聲明、導入和文檔字符串與 Java 中的類似,只是稍作修改。

以下IFoo.haltypes.hal示例說明了 HIDL 代碼樣式,並提供了每個樣式詳細信息的快速鏈接(已省略IFooClientCallback.halIBar.halIBaz.hal )。

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

命名約定

函數名、變量名和文件名應該是描述性的;避免過度縮寫。將首字母縮略詞視為單詞(例如,使用INfc代替INFC )。

目錄結構和文件命名

目錄結構應如下所示:

  • ROOT-DIRECTORY
    • MODULE
      • SUBMODULE (可選,可以多於一層)
        • VERSION
          • Android.mk
          • I INTERFACE_1 .hal
          • I INTERFACE_2 .hal
          • I INTERFACE_N .hal
          • types.hal (可選)

在哪裡:

  • ROOT-DIRECTORY是:
    • 核心 HIDL 包的hardware/interfaces
    • vendor/ VENDOR /interfaces ,其中供應VENDOR是指 SoC 供應商或 OEM/ODM。
  • MODULE應該是一個描述子系統的小寫單詞(例如nfc )。如果需要多個單詞,請使用嵌套SUBMODULE 。可以有不止一層嵌套。
  • VERSION應該與 Versions 中描述的版本完全相同(major.minor)。
  • I INTERFACE_X應該是接口名稱中的UpperCamelCase / PascalCase (例如INfc ),如接口名稱中所述。

例子:

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

注意:所有文件都必須具有不可執行的權限(在 Git 中)。

包名稱

包名稱必須使用以下完全限定名稱 (FQN)格式(稱為PACKAGE-NAME ):

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

在哪裡:

  • PACKAGE是映射到ROOT-DIRECTORY的包。特別是, PACKAGE是:
    • android.hardware用於核心 HIDL 包(映射到hardware/interfaces )。
    • vendor. VENDOR .hardware供應商包的vendor. VENDOR .hardware ,其中VENDOR指的是 SoC 供應商或 OEM/ODM(​​映射到vendor/ VENDOR /interfaces )。
  • MODULE [. SUBMODULE [. SUBMODULE […]]]@ VERSION目錄結構中描述的結構中的文件夾名稱完全相同。
  • 包名應該是小寫的。如果它們的長度超過一個單詞,則這些單詞應該用作子模塊或寫在snake_case中。
  • 不允許有空格。

FQN 始終用於包聲明中。

版本

版本應具有以下格式:

MAJOR.MINOR

MAJORMINOR版本都應該是一個整數。 HIDL 使用語義版本控制規則。

進口

導入具有以下三種格式之一:

  • 整包導入: import PACKAGE-NAME ;
  • 部分導入: import PACKAGE-NAME :: UDT ; (或者,如果導入的類型在同一個包中, import UDT ;
  • 僅類型導入: import PACKAGE-NAME ::types;

PACKAGE-NAME遵循Package names中的格式。當前包的types.hal (如果存在)會自動導入(不要顯式導入)。

完全限定名稱 (FQN)

僅在必要時對用戶定義的類型導入使用完全限定名稱。如果導入類型在同一個包中,則省略PACKAGE-NAME 。 FQN 不得包含空格。完全限定名稱的示例:

android.hardware.nfc@1.0::INfcClientCallback

android.hardware.nfc@1.0下的另一個文件中,將上述接口稱為INfcClientCallback 。否則,僅使用完全限定名稱。

對導入進行分組和排序

在包聲明後(導入前)使用空行。每個導入應佔一行並且不應縮進。按以下順序對導入進行分組:

  1. 其他android.hardware包(使用完全限定的名稱)。
  2. 其他vendor. VENDOR包(使用完全限定的名稱)。
    • 每個供應商都應該是一個組。
    • 按字母順序排列供應商。
  3. 從同一包中的其他接口導入(使用簡單名稱)。

在組之間使用空行。在每個組內,按字母順序對導入進行排序。例子:

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;

接口名稱

接口名稱必須以I開頭,後跟UpperCamelCase / PascalCase名稱。名稱為IFoo的接口必須在文件IFoo.hal中定義。該文件只能包含IFoo接口的定義(接口I NAME應該在I NAME .hal )。

功能

對於函數名稱、參數和返回變量名稱,請使用lowerCamelCase 。例子:

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

結構/聯合字段名稱

對於結構/聯合字段名稱,請使用lowerCamelCase 。例子:

struct FooReply {
    vec<uint8_t> replyData;
}

類型名稱

類型名稱是指結構/聯合定義、枚舉類型定義和typedef 。對於這些名稱,請使用UpperCamelCase / PascalCase 。例子:

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

枚舉值

枚舉值應該是UPPER_CASE_WITH_UNDERSCORES 。當將枚舉值作為函數參數傳遞並將它們作為函數返回時,請使用實際的枚舉類型(而不是底層整數類型)。例子:

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

注意:枚舉類型的基礎類型在冒號之後顯式聲明。由於它不依賴於編譯器,因此使用實際的枚舉類型更加清晰。

對於枚舉值的完全限定名稱,在枚舉類型名稱和枚舉值名稱之間使用冒號

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

完全限定名稱中不能有空格。僅在必要時使用完全限定名稱並省略不必要的部分。例子:

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

註釋

對於單行註釋, ///* *//** */都可以。

// This is a single line comment
/* This is also single line comment */
/** This is documentation comment */
  • 使用/* */進行註釋。雖然 HIDL 支持//用於註釋,但不鼓勵使用它們,因為它們不會出現在生成的輸出中。
  • 使用/** */生成文檔。這些只能應用於類型、方法、字段和枚舉值聲明。示例:
    /** 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,
        ...
    }
    
  • /**在單獨的行開始多行註釋。在每行的開頭使用* 。用*/在單獨的行結束註釋,對齊星號。示例:
    /**
     * My multi-line
     * comment
     */
    
  • 許可通知和變更日誌應以/* (單個星號)開始新的一行,在每行的開頭使用* ,並將*/單獨放在最後一行(星號應對齊)。示例:
    /*
     * Copyright (C) 2017 The Android Open Source Project
     * ...
     */
    
    /*
     * Changelog:
     * ...
     */
    

文件評論

以適當的許可通知開始每個文件。對於核心 HAL,這應該是development/docs/copyright-templates/c.txt中的 AOSP Apache 許可證。請記住更新年份並使用/* */樣式的多行註釋,如上所述。

您可以選擇在許可證通知之後放置一個空行,然後是更改日誌/版本信息。如上所述使用/* */樣式的多行註釋,將空行放在更改日誌之後,然後跟隨包聲明。

待辦事項評論

TODO 應包含全部大寫的字符串TODO ,後跟冒號。例子:

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

僅在開發期間允許 TODO 註釋;它們不得存在於已發布的接口中。

接口/函數註釋(文檔字符串)

對多行和單行文檔字符串使用/** */ 。不要將//用於文檔字符串。

接口的文檔字符串應該描述接口的一般機制、設計原理、用途等。函數的文檔字符串應該特定於函數(包級文檔位於包目錄中的 README 文件中)。

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

您必須為每個參數/返回值添加@param@return

  • 必須為每個參數添加@param 。它後面應該是參數的名稱,然後是文檔字符串。
  • @return必須為每個返回值添加。它後面應該是返回值的名稱,然後是文檔字符串。

例子:

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

格式化

一般格式規則包括:

  • 線長。每行文本最多應為100列。
  • 空格。行上沒有尾隨空格;空行不能包含空格。
  • 空格與製表符。僅使用空格。
  • 縮進大小。塊使用4 個空格,換行使用8個空格
  • 支撐。除了註釋值之外,大括號與前面的代碼在同一行,但大括號和後面的分號佔據整行。示例:
    interface INfc {
        close();
    };
    

包裝聲明

包聲明應該在許可通知之後的文件頂部,應該佔據整行,並且不應該縮進。使用以下格式聲明包(有關名稱格式,請參閱包名稱):

package PACKAGE-NAME;

例子:

package android.hardware.nfc@1.0;

函數聲明

如果合適的話,函數名、參數、 generates和返回值應該在同一行。例子:

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

如果它們不適合在同一行,請嘗試將參數和返回值放在相同的縮進級別並區分generate ,以幫助讀者快速查看參數和返回值。例子:

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

額外細節:

  • 左括號總是與函數名在同一行。
  • 函數名和左括號之間沒有空格。
  • 括號和參數之間沒有空格,除非它們之間有換行符。
  • 如果generates與前一個右括號在同一行,請使用前面的空格。如果generates與下一個左括號在同一行,請在後面加上一個空格。
  • 對齊所有參數和返回值(如果可能)。
  • 默認縮進為 4 個空格。
  • 包裝的參數與前一行的第一個參數對齊,否則它們有 8 個空格的縮進。

註釋

使用以下格式進行註釋:

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

按字母順序對註釋進行排序,並在等號周圍使用空格。例子:

@callflow(key = value)
@entry
@exit

確保註釋佔據整行。例子:

/* Good */
@entry
@exit

/* Bad */
@entry @exit

如果註釋不能放在同一行,縮進 8 個空格。例子:

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

如果整個值數組不能放在同一行中,請在大括號{和數組內的每個逗號之後放置換行符。在最後一個值之後立即放置右括號。如果只有一個值,請不要放置大括號。

如果整個值數組可以放在同一行中,請不要在左大括號之後和右大括號之前使用空格,並且在每個逗號之後使用一個空格。例子:

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

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

註釋和函數聲明之間不能有空行。例子:

/* Good */
@entry
foo();

/* Bad */
@entry

foo();

枚舉聲明

對枚舉聲明使用以下規則:

  • 如果枚舉聲明與另一個包共享,請將聲明放在types.hal中,而不是嵌入到接口中。
  • 在冒號之前和之後使用空格,在開括號之前的基礎類型之後使用空格。
  • 最後一個枚舉值可能有也可能沒有額外的逗號。

結構聲明

對結構聲明使用以下規則:

  • 如果結構聲明與另一個包共享,請將聲明放在types.hal中,而不是嵌入到接口中。
  • 在結構類型名稱之後,在左大括號之前使用一個空格。
  • 對齊字段名稱(可選)。示例:
    struct MyStruct {
        vec<uint8_t>   data;
        int32_t        someInt;
    }
    

數組聲明

請勿在以下內容之間放置空格:

  • 元素類型和開方括號。
  • 打開方括號和數組大小。
  • 數組大小和右方括號。
  • 如果存在多個維度,則關閉方括號和下一個打開方括號。

例子:

/* Good */
int32_t[5] array;

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

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

矢量圖

請勿在以下內容之間放置空格:

  • vec和開尖括號。
  • 打開尖括號和元素類型(例外:元素類型也是vec )。
  • 元素類型和右尖括號(例外:元素類型也是vec

例子:

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