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» ).
Интерфейсы размещаются в независимых от устройств местах.
На практике рекомендуется совместно использовать интерфейсы между филиалами. Это обеспечивает максимальное повторное использование кода и максимальное тестирование кода на разных устройствах и в различных сценариях использования.