Интерфейсы и пакеты

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.hal types пакета.

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

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

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

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 расширения (поставщика).

Версии

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

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

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

Сводка макета интерфейса

В этом разделе кратко описано, как управлять пакетом интерфейса HIDL (таким как hardware/interfaces ), и объединена информация, представленная в разделе HIDL. Прежде чем читать, убедитесь, что вы знакомы с HIDL Versioning , концепциями хеширования в Hashing with 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 option в hidl-gen (это подробно обсуждается в разделе «Хеширование с hidl-gen» ).

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

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