HIDL 程式碼風格類似於 Android 框架中的 C++ 程式碼,具有 4 個空格縮排和大小寫混合的檔案名稱。套件聲明、導入和文件字串與 Java 中的相似,但略有修改。
以下IFoo.hal
和types.hal
範例說明了 HIDL 程式碼樣式,並提供了有關每種樣式的詳細資訊的快速連結(已省略IFooClientCallback.hal
、 IBar.hal
和IBaz.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。
- 核心 HIDL 包的
-
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
指 SoC 供應商或 OEM/ODM(映射到vendor/ VENDOR /interfaces
)。
-
-
MODULE [. SUBMODULE [. SUBMODULE […]]]@ VERSION
目錄結構中所述的結構中的資料夾名稱完全相同。 - 包名稱應該小寫。如果它們超過一個單字長,則這些單字應該用作子模組或寫在
snake_case
中。 - 不允許有空格。
FQN 始終用於套件聲明中。
版本
版本應具有以下格式:
MAJOR.MINOR
MAJOR和MINOR版本都應該是單一整數。 HIDL 使用語意版本控制規則。
進口
導入具有以下三種格式之一:
- 整個套件導入:
import PACKAGE-NAME ;
- 部分導入:
import PACKAGE-NAME :: UDT ;
(或者,如果匯入的類型位於相同套件中,則import UDT ;
- 僅類型導入:
import PACKAGE-NAME ::types;
PACKAGE-NAME
遵循套件名稱中的格式。目前套件的types.hal
(如果存在)會自動導入(不要明確導入)。
完全限定名稱 (FQN)
僅在必要時才對使用者定義類型導入使用完全限定名稱。如果匯入類型位於相同套件中,則省略PACKAGE-NAME
。 FQN 不得包含空格。完全限定名稱的範例:
android.hardware.nfc@1.0::INfcClientCallback
在android.hardware.nfc@1.0
下的另一個檔案中,將上述介面引用為INfcClientCallback
。否則,僅使用完全限定名稱。
將導入進行分組和排序
在套件聲明之後(導入之前)使用空白行。每個導入應該佔據一行並且不應該縮排。按以下順序分組匯入:
- 其他
android.hardware
軟體包(使用完全限定名稱)。 - 其他
vendor. VENDOR
包(使用完全限定名稱)。- 每個供應商都應該是一個團體。
- 按字母順序對供應商進行排序。
- 從同一包中的其他介面匯入(使用簡單名稱)。
組之間使用空白行。在每個組內,按字母順序對導入進行排序。例子:
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.hal
中定義名為IFoo
的介面。該檔案只能包含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; }
類型名稱
類型名稱是指 struct/union 定義、枚舉類型定義和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
,後面跟著冒號。例子:
// 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;