В Android 8 переработана архитектура ОС Android, чтобы определить четкие интерфейсы между аппаратно-независимой платформой Android и кодом, зависящим от устройства и поставщика. Android уже определяет множество таких интерфейсов в форме интерфейсов HAL, определяемых как заголовки C в hardware/libhardware . HIDL заменяет эти интерфейсы HAL стабильными интерфейсами с поддержкой версий, которые могут быть интерфейсами HIDL на стороне клиента и сервера на C++ (описано ниже) или Java .
На страницах этого раздела описаны реализации интерфейсов HIDL на C++, включая сведения о файлах, автоматически создаваемых из файлов HIDL .hal компилятором hidl-gen , о том, как эти файлы упаковываются и как интегрировать эти файлы с кодом C++, который их использует.
Реализации клиента и сервера
HIDL-интерфейсы имеют клиентскую и серверную реализации:
- Клиент интерфейса HIDL — это код, который использует интерфейс, вызывая его методы.
- Сервер — это реализация HIDL-интерфейса, который принимает вызовы от клиентов и возвращает результаты (при необходимости).
При переходе от HAL libhardware к HAL HIDL реализация HAL становится сервером, а процесс, вызывающий HAL, становится клиентом. Реализации по умолчанию могут обслуживать как сквозные, так и связываемые HAL и могут меняться со временем:

Рисунок 1. Ход разработки устаревших HAL.
Создайте клиент HAL
Начните с включения библиотек HAL в make-файл:
- Сделать:
LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0 - Сун:
shared_libs: [ …, android.hardware.nfc@1.0 ]
Затем подключите заголовочные файлы HAL:
#include <android/hardware/nfc/1.0/IFoo.h> … // in code: sp<IFoo> client = IFoo::getService(); client->doThing();
Создайте HAL-сервер
Чтобы создать реализацию HAL, у вас должны быть файлы .hal , представляющие ваш HAL, и уже созданы файлы makefile для вашего HAL с помощью -Lmakefile или -Landroidbp в hidl-gen ( ./hardware/interfaces/update-makefiles.sh делает это для внутренних файлов HAL и является хорошим справочником). При переносе HAL из libhardware большую часть этой работы можно легко выполнить с помощью c2hal.
Чтобы создать необходимые файлы для реализации вашего HAL:
PACKAGE=android.hardware.nfc@1.0 LOC=hardware/interfaces/nfc/1.0/default/ m -j hidl-gen hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE
Чтобы HAL работал в режиме сквозной передачи, у вас должна быть функция HIDL_FETCH_IModuleName находящаяся в /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).so , где OPTIONAL_IDENTIFIER — это строка, идентифицирующая реализацию сквозной передачи. Требования режима сквозной передачи автоматически выполняются приведенными выше командами, которые также создают цель android.hardware.nfc@1.0-impl , но можно использовать любое расширение. Например, android.hardware.nfc@1.0-impl-foo использует -foo для дифференциации.
Если HAL является дополнительной версией или расширением другого HAL, для имени этого двоичного файла следует использовать базовый HAL. Например, реализации android.hardware.graphics.mapper@2.1 по-прежнему должны находиться в двоичном файле с именем android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER ) . Обычно OPTIONAL_IDENTIFIER здесь включает фактическую версию HAL. Назвав двоичный файл таким образом, клиенты 2.0 смогут получить его напрямую, а клиенты 2.1 — повысить реализацию.
Далее заполняем заглушки функционалом и настраиваем демона. Пример кода демона (поддерживающего сквозную передачу):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation вызывает dlopen() для предоставленной библиотеки -impl и предоставляет ее как службу с привязкой. Пример кода демона (для чистой службы связывания):
int main(int /* argc */, char* /* argv */ []) { // This function must be called before you join to ensure the proper // number of threads are created. The threadpool never exceeds // size one because of this call. ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); sp<INfc> nfc = new Nfc(); const status_t status = nfc->registerAsService(); if (status != ::android::OK) { return 1; // or handle error } // Adds this thread to the threadpool, resulting in one total // thread in the threadpool. We could also do other things, but // would have to specify 'false' to willJoin in configureRpcThreadpool. ::android::hardware::joinRpcThreadpool(); return 1; // joinRpcThreadpool should never return }
Этот демон обычно находится в $PACKAGE + "-service-suffix" (например, android.hardware.nfc@1.0-service ), но он может находиться где угодно. Политика конфиденциальности для определенного класса HAL — это атрибут hal_<module> (например, hal_nfc) . Этот атрибут должен быть применен к демону, который запускает определенный HAL (если один и тот же процесс обслуживает несколько HAL, к нему можно применить несколько атрибутов).