AIDL для HAL

В Android 11 появилась возможность использовать AIDL для HAL в Android. Это позволяет реализовать части Android без HIDL. Переключите HAL на использование только AIDL, где это возможно (когда вышестоящие HAL используют HIDL, необходимо использовать HIDL).

HAL, использующие AIDL для связи между компонентами инфраструктуры, такими как system.img , и аппаратными компонентами, такими как vendor.img , должны использовать Stable AIDL. Однако для связи внутри раздела, например, от одного HAL к другому, нет никаких ограничений на использование механизма IPC.

Мотивация

AIDL существует дольше, чем HIDL, и используется во многих других местах, например, между компонентами платформы Android или в приложениях. Теперь, когда AIDL имеет поддержку стабильности, можно реализовать весь стек с одной средой выполнения IPC. AIDL также имеет лучшую систему управления версиями, чем HIDL.

  • Использование единого языка IPC означает только одно, что нужно изучить, отладить, оптимизировать и защитить.
  • AIDL поддерживает управление версиями на месте для владельцев интерфейса:
    • Владельцы могут добавлять методы в конец интерфейсов или поля в объекты посылки. Это означает, что с годами легче обновлять код, а также стоимость из года в год меньше (типы можно изменять на месте, и нет необходимости в дополнительных библиотеках для каждой версии интерфейса).
    • Интерфейсы расширений могут быть присоединены во время выполнения, а не в системе типов, поэтому нет необходимости переустанавливать нисходящие расширения на более новые версии интерфейсов.
  • Существующий интерфейс AIDL можно использовать напрямую, когда его владелец решит стабилизировать его. Раньше в HIDL приходилось создавать полную копию интерфейса.

Написание интерфейса AIDL HAL

Для использования интерфейса AIDL между системой и поставщиком необходимо два изменения интерфейса:

  • Каждое определение типа должно быть аннотировано @VintfStability .
  • Объявление aidl_interface должно включать информацию о stability: "vintf",

Эти изменения может вносить только владелец интерфейса.

Кроме того, для максимальной переносимости кода и во избежание потенциальных проблем, таких как ненужные дополнительные библиотеки, отключите бэкэнд CPP.

Обратите внимание, что использование backends в приведенном ниже примере кода является правильным, поскольку существует три серверных модуля (Java, NDK и CPP). В приведенном ниже коде рассказывается, как конкретно выбрать серверную часть CPP, чтобы ее отключить.

    aidl_interface: {
        ...
        backends: {
            cpp: {
                enabled: false,
            },
        },
    }

Поиск интерфейсов AIDL HAL

Стабильные интерфейсы AIDL AOSP для HAL находятся в тех же базовых каталогах, что и интерфейсы HIDL, в aidl папках.

  • оборудование / интерфейсы
  • фреймворки / оборудование / интерфейсы
  • система / оборудование / интерфейсы

Вы должны поместить интерфейсы расширения в другие подкаталоги hardware/interfaces vendor или hardware .

Интерфейсы расширения

Android имеет набор официальных интерфейсов AOSP с каждым выпуском. Когда партнеры Android хотят добавить функциональность к этим интерфейсам, они не должны изменять их напрямую, потому что это будет означать, что их среда выполнения Android несовместима со средой выполнения AOSP Android. Для устройств GMS отказ от изменения этих интерфейсов также является гарантией продолжения работы образа GSI.

Расширения могут регистрироваться двумя разными способами:

Однако расширение регистрируется, когда компоненты, зависящие от поставщика (т. Е. Не являющиеся частью восходящего потока AOSP), используют интерфейс, вероятность конфликта слияния отсутствует. Однако при внесении последующих модификаций в вышестоящие компоненты AOSP могут возникнуть конфликты слияния, поэтому рекомендуются следующие стратегии:

  • дополнения интерфейса могут быть перенесены на AOSP в следующем выпуске
  • дополнения интерфейса, которые обеспечивают дополнительную гибкость без конфликтов слияния, могут быть обновлены в следующем выпуске

Опираясь на среду выполнения AIDL

AIDL имеет три разных серверных модуля: Java, NDK, CPP. Чтобы использовать стабильный AIDL, вы всегда должны использовать системную копию libbinder в system/lib*/libbinder.so и говорить о /dev/binder system/lib*/libbinder.so . Для кода в образе поставщика это означает, что libbinder (из VNDK) не может быть использован: эта библиотека имеет нестабильный C ++ API и нестабильные внутренние компоненты. Вместо этого собственный код поставщика должен использовать бэкэнд NDK для AIDL, связываться с libbinder_ndk (который поддерживается системой libbinder.so ) и связываться с библиотеками -ndk_platform созданными записями aidl_interface .

Имена экземпляров сервера AIDL HAL

По соглашению службы AIDL HAL имеют имя экземпляра в формате $package.$type/$instance . Например, экземпляр HAL вибратора регистрируется как android.hardware.vibrator.IVibrator/default .

Написание сервера AIDL HAL

Серверы AIDL должны быть объявлены в манифесте VINTF, например так:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

В противном случае они должны зарегистрировать службу AIDL обычным образом. При запуске тестов VTS ожидается, что будут доступны все заявленные HAL AIDL.

Написание клиента AIDL

Клиенты AIDL должны заявить о себе в матрице совместимости, например так:

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

Преобразование существующего HAL из HIDL в AIDL

Используйте инструмент hidl2aidl для преобразования интерфейса HIDL в AIDL.

hidl2aidl :

  • Создайте файлы .aidl на .hal файлов .hal для данного пакета.
  • Создайте правила сборки для вновь созданного пакета AIDL со всеми включенными серверными модулями.
  • Создайте методы перевода в бэкэндах Java, CPP и NDK для преобразования типов HIDL в типы AIDL.
  • Создавайте правила сборки для библиотек перевода с необходимыми зависимостями
  • Создайте статические утверждения, чтобы гарантировать, что перечислители HIDL и AIDL имеют одинаковые значения в бэкэндах CPP и NDK.

Выполните следующие действия, чтобы преобразовать пакет файлов .hal в файлы .aidl:

  1. Соберите инструмент, расположенный в system/tools/hidl/hidl2aidl .

    Сборка этого инструмента из новейшего источника обеспечивает наиболее полный опыт. Вы можете использовать последнюю версию для преобразования интерфейсов в более старых ветках из предыдущих выпусков.

    m hidl2aidl
    
  2. Запустите инструмент с выходным каталогом, за которым следует конвертируемый пакет.

    hidl2aidl -o <output directory> <package>
    

    Например:

    hidl2aidl -o . android.hardware.nfc@1.2
    
  3. Прочтите сгенерированные файлы и исправьте любые проблемы с преобразованием.

    • conversion.log содержит все необработанные проблемы, которые необходимо исправить в первую очередь.
    • Сгенерированные файлы .aidl могут содержать предупреждения и предложения, которые могут потребовать действий. Эти комментарии начинаются с // .
    • Воспользуйтесь возможностью, чтобы очистить и улучшить пакет.
  4. Стройте только те цели, которые вам нужны.

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

Сеполис для AIDL HAL

Тип службы AIDL, видимый для кода поставщика, должен иметь атрибут vendor_service . В остальном конфигурация sepolicy такая же, как и у любой другой службы AIDL.

    type hal_power_service, service_manager_type, vendor_service;

Для большинства служб, определенных платформой, контекст службы с правильным типом уже добавлен (например, android.hardware.power.IPower/default уже отмечен как hal_power_service ). Однако, если клиент платформы поддерживает несколько имен экземпляров, дополнительные имена экземпляров должны быть добавлены в файлы service_contexts конкретных устройств.

    android.hardware.power.IPower/custom_instance u:object_r:hal_power_service:s0

Прикрепленные интерфейсы расширения

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

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

Чтобы установить расширение для связующего, используйте следующие API:

  • В AIBinder_setExtension NDK: AIBinder_setExtension
  • В бэкэнде Java: android.os.Binder.setExtension
  • В android::Binder::setExtension CPP: android::Binder::setExtension

Чтобы получить расширение подшивки, используйте следующие API:

  • В AIBinder_getExtension NDK: AIBinder_getExtension
  • В бэкэнде Java: android.os.IBinder.getExtension
  • В android::IBinder::getExtension CPP: android::IBinder::getExtension

Вы можете найти дополнительную информацию об этих API в документации функции getExtension в соответствующем бэкэнде. Пример использования расширений можно найти в разделе hardware / interfaces / tests / extension / vibrator .

Основные различия AIDL / HIDL

При использовании AIDL HAL или интерфейсов AIDL HAL помните о различиях по сравнению с написанием HIDL HAL.

  • Синтаксис языка AIDL ближе к Java. Синтаксис HIDL аналогичен C ++.
  • Все интерфейсы AIDL имеют встроенные статусы ошибок. Вместо создания пользовательских типов состояния, создавать постоянный Интс состояния в файлах интерфейсы и использование EX_SERVICE_SPECIFIC в бэкэндах CPP / NDK и ServiceSpecificException в интерфейсе Java.
  • AIDL не запускает автоматически пулы потоков при отправке объектов подшивки. Их нужно запускать вручную (см. Управление потоками ).
  • AIDL не прерывается при непроверенных транспортных ошибках ( Return HIDL прерывается при непроверенных ошибках).
  • AIDL может объявлять только один тип для каждого файла.
  • Аргументы AIDL могут быть указаны как in / out / inout в дополнение к параметру вывода (нет «синхронных обратных вызовов»).
  • AIDL использует fd в качестве примитивного типа вместо дескриптора.
  • HIDL использует основные версии для несовместимых изменений и второстепенные версии для совместимых изменений. В AIDL изменения с обратной совместимостью выполняются на месте. AIDL не имеет четкого определения основных версий; вместо этого он включается в имена пакетов. Например, AIDL может использовать имя пакета bluetooth2 .