Стиль кода HIDL напоминает код C++ в платформе Android с отступами в 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
- это:-
hardware/interfaces
для основных пакетов HIDL. -
vendor/ VENDOR /interfaces
для пакетов поставщиков, гдеVENDOR
относится к поставщику SoC или OEM/ODM.
-
-
MODULE
должен состоять из одного слова в нижнем регистре, описывающего подсистему (например,nfc
). Если требуется более одного слова, используйте вложенныйSUBMODULE
. Может быть более одного уровня вложенности. -
VERSION
должна быть точно такой же версией (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
соответствует формату, указанному в Packagenames . types.hal
текущего пакета (если он существует) импортируется автоматически (не импортируйте его явно).
Полные имена (FQN)
Используйте полные имена для импорта определяемого пользователем типа только при необходимости. Опустите PACKAGE-NAME
, если тип импорта находится в том же пакете. Полное доменное имя не должно содержать пробелов. Пример полного имени:
android.hardware.nfc@1.0::INfcClientCallback
В другом файле android.hardware.nfc@1.0
назовите приведенный выше интерфейс INfcClientCallback
. В противном случае используйте только полное имя.
Группировка и упорядочивание импорта
Используйте пустую строку после объявления пакета (перед импортом). Каждый импорт должен занимать одну строку и не иметь отступов. Групповой импорт в следующем порядке:
- Другие пакеты
android.hardware
(используйте полные имена). - Другой
vendor. VENDOR
Пакеты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
должен быть определен в файле 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
s. Для этих имен используйте 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 это должна быть лицензия AOSP Apache в development/docs/copyright-templates/c.txt
. Не забудьте обновить год и использовать многострочные комментарии в стиле /* */
, как описано выше.
При желании вы можете разместить пустую строку после уведомления о лицензии, за которой следует журнал изменений/информация о версиях. Используйте многострочные комментарии в стиле /* */
как описано выше, поместите пустую строку после журнала изменений, а затем добавьте объявление пакета.
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;