Интерфейсы и усилители; Пакеты

HIDL построен на интерфейсах — абстрактном типе, используемом в объектно-ориентированных языках для определения поведения. Каждый интерфейс является частью пакета.

Пакеты

Имена пакетов могут иметь подуровни, например package.subpackage . Корневым каталогом для опубликованных пакетов HIDL является hardware/interfaces или vendor/vendorName (например vendor/google для устройств Pixel). Имя пакета образует один или несколько подкаталогов в корневом каталоге; все файлы, определяющие пакет, находятся в одном каталоге. Например, package android.hardware.example.extension.light@2.0 можно найти в разделе hardware/interfaces/example/extension/light/2.0 .

В следующей таблице перечислены префиксы и местоположения пакетов:

Префикс пакета Расположение Типы интерфейсов
android.hardware.* hardware/interfaces/* ХАЛ
android.frameworks.* frameworks/hardware/interfaces/* фреймворки/связанные
android.system.* system/hardware/interfaces/* система/связанная
android.hidl.* system/libhidl/transport/* основной

Каталог пакета содержит файлы с расширением .hal . Каждый файл должен содержать оператор package , в котором указывается имя пакета и версия, частью которого является файл. Файл types.hal , если он присутствует, не определяет интерфейс, а вместо этого определяет типы данных, доступные для каждого интерфейса в пакете.

Определение интерфейса

Помимо types.hal , каждый второй файл .hal определяет интерфейс. Интерфейс обычно определяется следующим образом:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

Интерфейс без явного объявления extends неявно расширяется от android.hidl.base@1.0::IBase (аналогично java.lang.Object в Java). Интерфейс IBase, неявно импортированный, объявляет несколько зарезервированных методов, которые не должны и не могут быть переобъявлены. в пользовательских интерфейсах или используется иным образом. Эти методы включают в себя:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

Импорт

Оператор import — это HIDL-механизм для доступа к интерфейсам и типам пакета в другом пакете. Оператор import касается двух объектов:

  • Импортирующий объект, который может быть либо пакетом, либо интерфейсом; и
  • Импортируемый объект, который также может быть пакетом или интерфейсом.

Импортирующая организация определяется местоположением заявления об import . Когда оператор находится внутри types.hal пакета, то, что импортируется, видно всему пакету; это импорт на уровне пакета . Когда оператор находится внутри файла интерфейса, импортирующей сущностью является сам интерфейс; это импорт на уровне интерфейса .

Импортируемый объект определяется значением после ключевого слова import . Значение не обязательно должно быть полным именем; если компонент опущен, он автоматически заполняется информацией из текущего пакета. Для полных значений поддерживаются следующие случаи импорта:

  • Импорт всей упаковки . Если значением является имя пакета и версия (синтаксис описан ниже), то весь пакет импортируется в импортирующий объект.
  • Частичный импорт . Если значение:
    • Интерфейс, types.hal пакета и этот интерфейс импортируются в импортирующий объект.
    • UDT, определенный в types.hal , затем в импортирующий объект импортируется только этот UDT (другие типы в types.hal не импортируются).
  • Импорт только типов . Если значение использует синтаксис частичного импорта, описанный выше, но с ключевыми словами types вместо имени интерфейса, импортируются только определяемые пользователем типы в types.hal назначенного пакета.

Импортирующая организация получает доступ к комбинации:

  • Общие UDT импортированного пакета, определенные в types.hal ;
  • Интерфейсы импортированного пакета (для импорта всего пакета) или указанного интерфейса (для частичного импорта) с целью их вызова, передачи их дескрипторов и/или наследования от них.

Оператор импорта использует синтаксис полного имени типа для предоставления имени и версии импортируемого пакета или интерфейса:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

Наследование интерфейса

Интерфейс может быть расширением ранее определенного интерфейса. Расширения могут быть одного из следующих трех типов:

  • Интерфейс может добавлять функциональность к другому, включая его API без изменений.
  • Пакет может добавлять функциональность к другому, включая его API без изменений.
  • Интерфейс может импортировать типы из пакета или из определенного интерфейса.

Интерфейс может расширять только один другой интерфейс (без множественного наследования). Каждый интерфейс в пакете с ненулевым дополнительным номером версии должен расширять интерфейс предыдущей версии пакета. Например, если интерфейс IBar в версии 4.0 derivative пакета основан на (расширяет) интерфейс IFoo в версии 1.2 пакета original и создается версия 1.3 original пакета, IBar версии 4.1 не может расширять версию 1.3 IFoo . Вместо этого IBar версии 4.1 должен расширять IBar версии 4.0, которая привязана к IFoo версии 1.2. IBar версии 5.0 при желании может расширить IFoo версии 1.3.

Расширения интерфейса не подразумевают зависимость от библиотеки или включение перекрестного HAL в сгенерированный код — они просто импортируют структуру данных и определения методов на уровне HIDL. Каждый метод в HAL должен быть реализован в этом HAL.

Расширения поставщиков

В некоторых случаях расширения поставщиков будут реализованы как подкласс базового объекта, который представляет основной интерфейс, который они расширяют. Один и тот же объект будет зарегистрирован под базовым именем и версией HAL, а также под именем и версией HAL расширения (поставщика).

Управление версиями

Пакеты имеют версии, а интерфейсы имеют версию своего пакета. Версии выражаются двумя целыми числами, major . незначительный .

  • Основные версии не имеют обратной совместимости. Увеличение основного номера версии сбрасывает дополнительный номер версии на 0.
  • Второстепенные версии обратно совместимы. Увеличение младшего номера указывает на то, что новая версия полностью обратно совместима с предыдущей версией. Можно добавлять новые структуры данных и методы, но нельзя изменять существующие структуры данных или сигнатуры методов.

На устройстве одновременно могут присутствовать несколько основных или второстепенных версий HAL. Однако второстепенная версия должна быть предпочтительнее основной версии, поскольку клиентский код, который работает с интерфейсом предыдущей второстепенной версии, также будет работать с более поздними второстепенными версиями того же интерфейса. Дополнительные сведения об управлении версиями и расширениях поставщиков см. в разделе Управление версиями HIDL .

Краткое описание макета интерфейса

В этом разделе описывается, как управлять пакетом интерфейсов HIDL (например, hardware/interfaces ), а также консолидируется информация, представленная в разделе HIDL. Перед чтением убедитесь, что вы знакомы с управлением версиями HIDL , концепциями хеширования в разделе «Хеширование с помощью hidl-gen» , деталями работы с HIDL в целом и следующими определениями:

Срок Определение
Двоичный интерфейс приложения (ABI) Интерфейс прикладного программирования + любые необходимые двоичные связи.
Полное имя (fqName) Имя, позволяющее отличить тип hidl. Пример: android.hardware.foo@1.0::IFoo .
Упаковка Пакет, содержащий интерфейс и типы HIDL. Пример: android.hardware.foo@1.0 .
Корень пакета Корневой пакет, содержащий интерфейсы HIDL. Пример: интерфейс HIDL android.hardware находится в корне пакета android.hardware.foo@1.0 .
Корневой путь пакета Местоположение в дереве исходного кода Android, которому соответствует корень пакета.

Дополнительные определения см. в разделе Терминология HIDL.

Каждый файл можно найти по сопоставлению корня пакета и его полному имени.

Корни пакетов указываются в hidl-gen как аргумент -r android.hardware:hardware/interfaces . Например, если пакет vendor.awesome.foo@1.0::IFoo и hidl-gen отправлен -r vendor.awesome:some/device/independent/path/interfaces , то файл интерфейса должен находиться в $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal .

На практике поставщикам или OEM-производителям с именем awesome рекомендуется поместить свои стандартные интерфейсы в vendor.awesome . После выбора пути к пакету его нельзя изменять, поскольку он встроен в ABI интерфейса.

Сопоставление пути к пакету должно быть уникальным.

Например, если у вас есть -rsome.package:$PATH_A и -rsome.package:$PATH_B , $PATH_A должен быть равен $PATH_B для согласованного каталога интерфейса (это также значительно упрощает управление версиями интерфейсов ).

В корне пакета должен быть файл версии.

Если вы создаете путь к пакету, например -r vendor.awesome:vendor/awesome/interfaces , вам также следует создать файл $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt , который должен содержать хэши интерфейсов, созданных с использованием -Lhash опция в hidl-gen (это подробно обсуждается в разделе Хеширование с помощью hidl-gen ).

Интерфейсы располагаются в местах, независимых от устройства.

На практике рекомендуется разделять интерфейсы между филиалами. Это позволяет максимально повторно использовать код и максимально тестировать его на разных устройствах и в разных сценариях использования.