HIDL построен на интерфейсах — абстрактном типе, используемом в объектно-ориентированных языках для определения поведения. Каждый интерфейс является частью пакета.
Пакеты
Имена пакетов могут иметь подуровни, например package.subpackage
. Корневым каталогом для опубликованных пакетов HIDL является hardware/interfaces
илиvendor 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 ).
Интерфейсы располагаются в местах, независимых от устройства.
На практике мы рекомендуем разделять интерфейсы между филиалами. Это позволяет максимально повторно использовать код и максимально тестировать его на разных устройствах и в разных сценариях использования.