В Android 11 появилась возможность использовать AIDL для HAL в Android, что позволяет реализовывать части Android без HIDL. Перевести HAL на использование AIDL исключительно везде, где это возможно (если вышестоящие HAL используют HIDL, HIDL должен использоваться).
 HAL, использующие AIDL для взаимодействия между компонентами фреймворка, например, в system.img , и компонентами оборудования, например, в vendor.img , должны использовать стабильный AIDL. Однако для взаимодействия внутри раздела, например, между одним HAL, нет ограничений на использование механизма IPC.
Мотивация
AIDL существует дольше, чем HIDL, и используется во многих других областях, например, между компонентами фреймворка Android или в приложениях. Теперь, когда AIDL поддерживает стабильность, можно реализовать целый стек с помощью единой среды выполнения IPC. AIDL также имеет более эффективную систему управления версиями, чем HIDL. Вот некоторые преимущества AIDL:
- Использование одного языка IPC означает, что придется изучать, отлаживать, оптимизировать и обеспечивать безопасность только одного объекта.
 -  AIDL поддерживает управление версиями на месте для владельцев интерфейса:
- Владельцы могут добавлять методы в конец интерфейсов или поля в разделяемые объекты. Это упрощает версионирование кода на протяжении многих лет, а также снижает ежегодные затраты (типы можно изменять на месте, и нет необходимости в дополнительных библиотеках для каждой версии интерфейса).
 - Интерфейсы расширения можно присоединять во время выполнения, а не в системе типов, поэтому нет необходимости переносить нижестоящие расширения на более новые версии интерфейсов.
 
 - Существующий интерфейс AIDL можно использовать напрямую, если его владелец решит стабилизировать его. Раньше для этого приходилось создавать полную копию интерфейса в HIDL.
 
Сборка с использованием среды выполнения AIDL
 AIDL имеет три различных бэкенда: Java, NDK и CPP. Чтобы использовать стабильную версию AIDL, всегда используйте системную копию libbinder в system/lib*/libbinder.so и пишите на /dev/binder . Для кода в образе vendor это означает, что libbinder (из VNDK) не может быть использован: эта библиотека имеет нестабильный API C++ и нестабильные внутренние компоненты. Вместо этого, собственный код поставщика должен использовать бэкенд NDK AIDL, компоноваться с libbinder_ndk (который поддерживается системным libbinder.so ) и компоноваться с библиотеками NDK, созданными записями aidl_interface . Точные имена модулей см. в разделе «Правила именования модулей» .
Написать интерфейс AIDL HAL
Для использования интерфейса AIDL между системой и поставщиком необходимо внести два изменения в интерфейс:
-  Каждое определение типа должно быть аннотировано 
@VintfStability. -  Декларация 
aidl_interfaceдолжна включать в себяstability: "vintf",. 
Эти изменения может вносить только владелец интерфейса.
 При внесении этих изменений интерфейс должен быть в манифесте VINTF для корректной работы. Проверьте это (и связанные с этим требования, например, проверку заморозки освобожденных интерфейсов) с помощью теста vts_treble_vintf_vendor_test из набора тестов Vendor Test Suite (VTS) . Вы можете использовать интерфейс @VintfStability без этих требований, вызвав AIBinder_forceDowngradeToLocalStability в бэкенде NDK, android::Stability::forceDowngradeToLocalStability в бэкенде C++ или android.os.Binder#forceDowngradeToSystemStability в бэкенде Java для объекта связывателя перед его отправкой в другой процесс.
Кроме того, для максимальной переносимости кода и во избежание потенциальных проблем, таких как ненужные дополнительные библиотеки, отключите бэкэнд CPP.
Код показывает, как отключить бэкэнд CPP:
    aidl_interface: {
        ...
        backend: {
            cpp: {
                enabled: false,
            },
        },
    }
Найти интерфейсы AIDL HAL
 Стабильные интерфейсы AIDL AOSP для HALS находятся в папках aidl в тех же базовых каталогах, что и интерфейсы HIDL:
-  
hardware/interfaces— для интерфейсов, обычно предоставляемых аппаратным обеспечением. -  
frameworks/hardware/interfacesпредназначен для высокоуровневых интерфейсов, предоставляемых оборудованию. -  
system/hardware/interfacesпредназначен для низкоуровневых интерфейсов, предоставляемых оборудованию. 
 Поместите интерфейсы расширения в другие подкаталоги hardware/interfaces в vendor или hardware .
Интерфейсы расширения
В каждом выпуске Android есть набор официальных интерфейсов AOSP. Когда партнёры Android хотят расширить возможности этих интерфейсов, им не следует изменять их напрямую, поскольку это делает их среду выполнения Android несовместимой с средой выполнения Android AOSP. Избегайте изменения этих интерфейсов, чтобы образ GSI мог продолжать работать.
Расширения можно зарегистрировать двумя способами:
- Во время выполнения; см. Прикрепленные интерфейсы расширения
 - Как самостоятельный препарат, зарегистрированный глобально и в VINTF
 
Однако расширение зарегистрировано, когда компоненты, специфичные для поставщика (т. е. не являющиеся частью вышестоящего AOSP), используют интерфейс, конфликты слияния невозможны. Однако при внесении нижестоящих изменений в вышестоящие компоненты AOSP могут возникнуть конфликты слияния, и рекомендуются следующие стратегии:
- В следующем выпуске следует обновить интерфейсные дополнения к AOSP.
 - Дополнения к интерфейсу, обеспечивающие большую гибкость (без конфликтов слияния) в следующем выпуске.
 
Расширение parcelables: ParcelableHolder
 ParcelableHolder — это экземпляр интерфейса Parcelable , который может содержать другой экземпляр Parcelable .
 Основной вариант использования ParcelableHolder — обеспечение расширяемости Parcelable . Например, разработчики устройств ожидают возможности расширения Parcelable , определенного в AOSP AospDefinedParcelable , для включения дополнительных функций.
 Используйте интерфейс ParcelableHolder для расширения Parcelable вашими дополнительными функциями. Интерфейс ParcelableHolder содержит экземпляр Parcelable . Попытка добавить поля в Parcelable напрямую приведет к ошибке:
parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}
 Как видно из предыдущего кода, эта практика нарушена, поскольку поля, добавленные разработчиком устройства, могут конфликтовать при обновлении Parcelable в следующих версиях Android.
 Используя ParcelableHolder , владелец parcelable может определить точку расширения в экземпляре Parcelable :
parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}
 Затем разработчики устройств могут определить собственный экземпляр Parcelable для своего расширения:
parcelable OemDefinedParcelable {
  String x;
  int[] y;
}
 Новый экземпляр Parcelable можно прикрепить к исходному Parcelable с помощью поля ParcelableHolder :
// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;
ap.extension.setParcelable(op);
...
OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);
// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();
ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);
...
std::shared_ptr<OemDefinedParcelable> op_ptr;
ap.extension.getParcelable(&op_ptr);
// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);
...
std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);
// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });
ap.extension.set_parcelable(Rc::clone(&op));
...
let op = ap.extension.get_parcelable::<OemDefinedParcelable>();
Имена экземпляров сервера AIDL HAL
 По соглашению, службы AIDL HAL имеют имя экземпляра в формате $package.$type/$instance . Например, экземпляр HAL вибратора регистрируется как android.hardware.vibrator.IVibrator/default .
Напишите сервер AIDL HAL
 @VintfStability Серверы AIDL должны быть объявлены в манифесте VINTF, например:
    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>
В противном случае им следует зарегистрировать службу AIDL в обычном режиме. При выполнении тестов VTS ожидается, что все заявленные уровни доступа AIDL HAL доступны.
Напишите клиент 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 ( 
.aidl) на основе файлов HAL (.hal) для данного пакета. - Создайте правила сборки для недавно созданного пакета AIDL со всеми включенными бэкэндами.
 - Создайте методы перевода в бэкэндах Java, CPP и NDK для перевода из типов HIDL в типы AIDL.
 - Создайте правила сборки для библиотек перевода с необходимыми зависимостями.
 - Создайте статические утверждения, чтобы гарантировать, что перечислители HIDL и AIDL имеют одинаковые значения в бэкэндах CPP и NDK.
 
Чтобы преобразовать пакет файлов HAL в файлы AIDL, выполните следующие действия:
Создайте инструмент, расположенный в
system/tools/hidl/hidl2aidl.Сборка этого инструмента из последней версии исходного кода обеспечивает наиболее полный функционал. Вы можете использовать последнюю версию для конвертации интерфейсов в старых ветках из предыдущих выпусков:
m hidl2aidlЗапустите инструмент, указав выходной каталог и пакет, который необходимо преобразовать.
При желании используйте аргумент
-l, чтобы добавить содержимое нового файла лицензии в начало всех сгенерированных файлов. Убедитесь, что указаны корректные лицензия и дата:hidl2aidl -o <output directory> -l <file with license> <package>Например:
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2Прочитайте сгенерированные файлы и исправьте любые проблемы с преобразованием:
-  
conversion.logсодержит все необработанные проблемы, которые следует исправить в первую очередь. -  Сгенерированные файлы AIDL могут содержать предупреждения и предложения, требующие действий. Эти комментарии начинаются с 
//. - Очистите и внесите улучшения в пакет.
 -  Проверьте аннотацию 
@JavaDeriveна наличие функций, которые могут потребоваться, напримерtoStringилиequals. 
-  
 Создавайте только те цели, которые вам нужны:
- Отключите бэкенды, которые не будут использоваться. Отдавайте предпочтение бэкенду NDK, а не бэкенду CPP; см. раздел Сборка с использованием среды выполнения AIDL .
 - Удалите библиотеки трансляции и любой сгенерированный ими код, который не будет использоваться.
 
См. основные различия AIDL и HIDL :
-  Использование встроенных в AIDL 
Statusи исключений обычно улучшает интерфейс и устраняет необходимость в другом типе статуса, специфичном для интерфейса. -  Аргументы интерфейса AIDL в методах по умолчанию не являются 
@nullable, как в HIDL. 
-  Использование встроенных в AIDL 
 
SEPolicy для AIDL HAL
 Тип службы AIDL, видимый коду поставщика, должен иметь атрибут hal_service_type . В противном случае конфигурация sepolicy аналогична конфигурации любой другой службы AIDL (хотя для HAL есть специальные атрибуты). Вот пример определения контекста службы HAL: 
    type hal_foo_service, service_manager_type, hal_service_type;
Для большинства служб, определяемых платформой, контекст службы с правильным типом уже добавлен (например, android.hardware.foo.IFoo/default уже помечен как hal_foo_service ). Однако, если клиент фреймворка поддерживает несколько имён экземпляров, необходимо добавить дополнительные имена экземпляров в файлы service_contexts для конкретного устройства: 
    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0
При создании нового типа HAL необходимо добавить атрибуты HAL. Конкретный атрибут HAL может быть связан с несколькими типами служб (каждый из которых может иметь несколько экземпляров, как уже обсуждалось). Для HAL foo существует hal_attribute(foo) . Этот макрос определяет атрибуты hal_foo_client и hal_foo_server . Для заданного домена макросы hal_client_domain и hal_server_domain связывают домен с заданным атрибутом HAL. Например, если системный сервер является клиентом этого HAL, то применяется политика hal_client_domain(system_server, hal_foo) . Сервер HAL аналогично включает hal_server_domain(my_hal_domain, hal_foo) .
 Обычно для заданного атрибута HAL также создается домен, например hal_foo_default для справки или примеров HAL. Однако некоторые устройства используют эти домены для своих собственных серверов. Различие между доменами для нескольких серверов имеет значение только в том случае, если несколько серверов обслуживают один и тот же интерфейс и требуют разных наборов разрешений в своих реализациях. Во всех этих макросах hal_foo не является объектом sepolicy. Вместо этого этот токен используется этими макросами для обозначения группы атрибутов, связанных с парой клиент-сервер.
 Однако пока что hal_foo_service и hal_foo (пара атрибутов из hal_attribute(foo) ) не связаны. Атрибут HAL связывается со службами AIDL HAL с помощью макроса hal_attribute_service (в HIDL HAL используется макрос hal_attribute_hwservice ), например, hal_attribute_service(hal_foo, hal_foo_service) . Это означает, что процессы hal_foo_client могут получить доступ к HAL, а процессы hal_foo_server могут зарегистрировать HAL. Соблюдение этих правил регистрации осуществляется менеджером контекста ( servicemanager ).
 Имена служб могут не всегда соответствовать атрибутам HAL, например, hal_attribute_service(hal_foo, hal_foo2_service) . В общем случае, поскольку это подразумевает, что службы всегда используются вместе, можно удалить hal_foo2_service и использовать hal_foo_service для всех контекстов служб. Когда HAL устанавливают несколько экземпляров hal_attribute_service , это происходит потому, что исходное имя атрибута HAL недостаточно общее и не может быть изменено.
Если собрать все вместе, то пример HAL выглядит так:
    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)
    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type
    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)
    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0
    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)
    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)
Прикрепленные интерфейсы расширения
Расширение можно прикрепить к любому интерфейсу связующего устройства, будь то интерфейс верхнего уровня, зарегистрированный непосредственно в диспетчере служб, или подынтерфейс. При получении расширения необходимо убедиться, что тип расширения соответствует ожидаемому. Расширения можно устанавливать только из процесса, обслуживающего связующее устройство.
Используйте прикреплённые расширения всякий раз, когда расширение изменяет функциональность существующего уровня HAL. Когда требуются совершенно новые возможности, этот механизм не нужен, и вы можете зарегистрировать интерфейс расширения напрямую в диспетчере служб. Прикреплённые интерфейсы расширения наиболее целесообразны при подключении к подинтерфейсам, поскольку эти иерархии могут быть глубокими или многоэкземплярными. Использование глобального расширения для зеркалирования иерархии интерфейсов связующего компонента другой службы требует обширного учёта для предоставления возможностей, эквивалентных напрямую прикреплённым расширениям.
Чтобы установить расширение для подшивки, используйте следующие API:
-  Бэкэнд NDK: 
AIBinder_setExtension -  Java-бэкэнд: 
android.os.Binder.setExtension -  CPP-бэкэнд: 
android::Binder::setExtension -  Бэкэнд Rust: 
binder::Binder::set_extension 
Чтобы получить расширение для подшивки, используйте следующие API:
-  Серверная часть NDK: 
AIBinder_getExtension -  Серверная часть Java: 
android.os.IBinder.getExtension -  Серверная часть CPP: 
android::IBinder::getExtension -  Бэкэнд Rust: 
binder::Binder::get_extension 
 Дополнительную информацию об этих 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 не прерывает работу при непроверенных ошибках транспортировки (HIDL 
Returnпрерывает работу при непроверенных ошибках). - AIDL может объявить только один тип для одного файла.
 -  Аргументы AIDL могут быть указаны как 
in,outилиinoutв дополнение к параметру output (синхронные обратные вызовы отсутствуют). -  AIDL использует 
fdв качестве примитивного типа вместоhandle. -  HIDL использует основные версии для несовместимых изменений и второстепенные версии для совместимых. В AIDL обратно совместимые изменения выполняются на месте. В AIDL нет явного понятия основных версий; вместо этого оно включено в имена пакетов. Например, AIDL может использовать имя пакета 
bluetooth2. -  AIDL по умолчанию не наследует приоритет реального времени. Для включения наследования приоритета реального времени необходимо использовать функцию 
setInheritRtдля каждого биндера. 
Тесты для HAL
В этом разделе описаны рекомендации по тестированию HAL. Эти рекомендации применимы даже в том случае, если интеграционный тест вашего HAL отсутствует в VTS .
Android использует VTS для проверки ожидаемых реализаций HAL. VTS обеспечивает обратную совместимость Android со старыми реализациями поставщиков. Реализации, не прошедшие проверку VTS, имеют известные проблемы совместимости, которые могут помешать им работать с будущими версиями ОС.
Система VTS для HAL состоит из двух основных частей.
1. Убедитесь, что HAL на устройстве известны и ожидаются Android.
Android требует наличия статичного и точного списка всех установленных уровней HAL. Этот список представлен в манифесте VINTF . Специальные общеплатформенные тесты проверяют целостность уровней HAL во всей системе. Перед написанием любых тестов, специфичных для HAL, следует также запустить эти тесты, поскольку они могут определить, имеет ли HAL несогласованные конфигурации VINTF.
 Этот набор тестов находится в test/vts-testcase/hal/treble/vintf . Если вы работаете над реализацией HAL от поставщика, используйте vts_treble_vintf_vendor_test для её проверки. Вы можете запустить этот тест командой atest vts_treble_vintf_vendor_test .
Эти тесты отвечают за проверку:
-  Каждый интерфейс 
@VintfStability, объявленный в манифесте VINTF, зафиксирован на известной выпущенной версии. Это подтверждает, что обе стороны интерфейса согласны с точным определением этой версии. Это необходимо для базовой работы. - Все HAL, объявленные в манифесте VINTF, доступны на этом устройстве. Любой клиент, имеющий достаточные разрешения для использования объявленной службы HAL, должен иметь возможность получить и использовать эти службы в любое время.
 - Все HAL, объявленные в манифесте VINTF, обслуживают версию интерфейса, объявленную в манифесте.
 - На устройстве не обслуживаются устаревшие версии HAL. Android прекращает поддержку более ранних версий интерфейсов HAL, как описано в жизненном цикле FCM .
 - На устройстве присутствуют необходимые HAL-файлы. Некоторые HAL-файлы необходимы для корректной работы Android.
 
2. Проверьте ожидаемое поведение каждого HAL.
Для каждого интерфейса HAL предусмотрены собственные тесты VTS для проверки ожидаемого поведения клиентов. Тестовые случаи выполняются для каждого экземпляра заявленного интерфейса HAL и обеспечивают определённое поведение в зависимости от версии реализованного интерфейса.
 В C++ получить список всех HAL, установленных в системе, можно с помощью функции android::getAidlHalInstanceNames в libaidlvintf_gtest_helper . В Rust используйте binder::get_declared_instances .
Эти тесты пытаются охватить все аспекты реализации HAL, на которые опирается фреймворк Android или на которые он может опираться в будущем.
Эти тесты включают проверку поддержки функций, обработки ошибок и любого другого поведения, которое клиент может ожидать от сервиса.
Основные этапы разработки VTS для HAL
Ожидается, что тесты VTS (или любые другие тесты) будут обновляться при создании или изменении интерфейсов HAL Android.
Тесты VTS должны быть завершены и готовы к проверке реализаций вендоров до их заморозки для выпуска API вендоров Android. Они должны быть готовы до заморозки интерфейсов, чтобы разработчики могли создать свои реализации, проверить их и предоставить обратную связь разработчикам интерфейсов HAL.
Тест на каракатице
При отсутствии необходимого оборудования Android использует Cuttlefish в качестве инструмента разработки интерфейсов HAL. Это позволяет проводить масштабируемое интеграционное тестирование Android.
 hal_implementation_test проверяет, что Cuttlefish имеет реализации последних версий интерфейса HAL, чтобы убедиться, что Android готов обрабатывать новые интерфейсы, а тесты VTS готовы тестировать реализации новых поставщиков, как только станут доступны новое оборудование и устройства.