Google is committed to advancing racial equity for Black communities. See how.
Эта страница была переведа с помощью Cloud Translation API.
Switch to English

Руководство по стилю кода

Стиль кода 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 следует формату в именах пакетов . Текущий пакет types.hal (если он существует) автоматически импортируется (не импортируйте его явно).

Полные имена (FQN)

Используйте полностью определенные имена для импорта определяемого пользователем типа только при необходимости. Опустите PACKAGE-NAME если тип импорта находится в том же пакете. FQN не должен содержать пробелов. Пример полного имени:

android.hardware.nfc@1.0::INfcClientCallback

В другом файле под android.hardware.nfc@1.0 INfcClientCallback указанный выше интерфейс INfcClientCallback . В противном случае используйте только полное имя.

Группировка и упорядочивание импорта

Используйте пустую строку после объявления пакета (перед импортом). Каждый импорт должен занимать одну строку без отступа. Группируйте импорт в следующем порядке:

  1. Другие пакеты android.hardware (используйте полностью определенные имена).
  2. Другой vendor. VENDOR Пакеты 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 должны быть 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 s и @return s для каждого параметра / возвращаемого значения:

  • @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();

Объявления перечисления

Используйте следующие правила для объявлений enum:

  • Если объявления перечисления используются совместно с другим пакетом, поместите объявления в 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;