HIDL Java

В Android 8.0 ОС Android была перестроена, чтобы определить четкие интерфейсы между независимой от устройства платформой Android и кодом, зависящим от устройства и поставщика. Android уже определил многие такие интерфейсы в виде интерфейсов HAL, определенных как заголовки C в hardware/libhardware . HIDL заменил эти интерфейсы HAL стабильными версионными интерфейсами, которые могут быть либо на Java (описаны ниже), либо быть клиентскими и серверными интерфейсами HIDL на C++ .

Интерфейсы HIDL предназначены для использования в первую очередь из собственного кода, поэтому HIDL ориентирован на автоматическое создание эффективного кода на C++. Однако интерфейсы HIDL также должны быть доступны для использования непосредственно из Java, поскольку некоторые подсистемы Android (например, телефония) имеют интерфейсы Java HIDL.

Страницы в этом разделе описывают внешний интерфейс Java для интерфейсов HIDL, подробно описывают, как создавать, регистрировать и использовать службы, а также объясняют, как HAL и клиенты HAL, написанные на Java, взаимодействуют с системой HIDL RPC.

Быть клиентом

Это пример клиента для интерфейса IFoo в пакете android.hardware.foo@1.0 , зарегистрированного как имя службы default , и дополнительной службы с именем настраиваемой службы second_impl .

Добавление библиотек

Вам нужно добавить зависимости от соответствующей библиотеки-заглушки HIDL, если вы хотите ее использовать. Обычно это статическая библиотека:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Если вы знаете, что уже используете зависимости от этих библиотек, вы также можете использовать общую компоновку:

// in Android.bp
libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Дополнительные рекомендации по добавлению библиотек в Android 10

Если у вас есть системное приложение или приложение поставщика, предназначенное для Android 10 или более поздней версии, вы можете статически включить эти библиотеки. Вы также можете использовать (только) классы HIDL из пользовательских JAR-файлов, установленных на устройстве, со стабильными API-интерфейсами Java, доступными с помощью существующего механизма uses-library для системных приложений. Последний подход экономит место на устройстве. Дополнительные сведения см. в разделе Реализация библиотеки Java SDK . Для старых приложений сохраняется старое поведение.

Начиная с Android 10, также доступны «поверхностные» версии этих библиотек. Они включают рассматриваемый класс, но не включают ни один из зависимых классов. Например, android.hardware.foo-V1.0-java-shallow включает классы в пакет foo, но не включает классы в android.hidl.base-V1.0-java , который содержит базовый класс всех HIDL. интерфейсы. Если вы создаете библиотеку, в которой базовые классы предпочтительного интерфейса уже доступны в качестве зависимости, вы можете использовать следующее:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java-shallow", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow

Библиотеки базы и менеджера HIDL также больше не доступны в загрузочном пути к классам для приложений (ранее они иногда использовались как скрытый API из-за загрузчика классов Android с первым делегированием). Вместо этого они были перемещены в новое пространство имен с помощью jarjar , и приложения, которые их используют (обязательно приватные приложения), должны иметь свои собственные отдельные копии. Модули в загрузочном пути к классам, использующие HIDL, должны использовать неглубокие варианты этих библиотек Java и добавить jarjar_rules: ":framework-jarjar-rules" в свой Android.bp , чтобы использовать версию этих библиотек, которая существует в загрузочном пути к классам.

Изменение исходного кода Java

Существует только одна версия ( @1.0 ) этой службы, поэтому этот код извлекает только эту версию. См. расширения интерфейса, чтобы узнать, как работать с несколькими разными версиями службы.

import android.hardware.foo.V1_0.IFoo;
...
// retry to wait until the service starts up if it is in the manifest
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IFoo anotherServer = IFoo.getService("second_impl", true /* retry */);
server.doSomething(…);

Предоставление услуги

Коду платформы на Java может потребоваться обслуживать интерфейсы для получения асинхронных обратных вызовов от HAL.

Для интерфейса IFooCallback в версии 1.0 пакета android.hardware.foo вы можете реализовать свой интерфейс на Java, выполнив следующие шаги:

  1. Определите свой интерфейс в HIDL.
  2. Откройте /tmp/android/hardware/foo/IFooCallback.java в качестве ссылки.
  3. Создайте новый модуль для реализации Java.
  4. Изучите абстрактный класс android.hardware.foo.V1_0.IFooCallback.Stub , затем напишите новый класс для его расширения и реализации абстрактных методов.

Просмотр автоматически сгенерированных файлов

Чтобы просмотреть автоматически сгенерированные файлы, запустите:

hidl-gen -o /tmp -Ljava \
  -randroid.hardware:hardware/interfaces \
  -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0

Эти команды создают каталог /tmp/android/hardware/foo/1.0 . Для файла hardware/interfaces/foo/1.0/IFooCallback.hal создается файл /tmp/android/hardware/foo/1.0/IFooCallback.java , который инкапсулирует интерфейс Java, код прокси и заглушки (оба прокси и заглушки соответствуют интерфейсу).

-Lmakefile генерирует правила, запускающие эту команду во время сборки, и позволяют включать android.hardware.foo-V1.0-java и связывать соответствующие файлы. Сценарий, который автоматически делает это для проекта, полного интерфейсов, можно найти по адресу hardware/interfaces/update-makefiles.sh . Пути в этом примере относительные; hardware/interfaces может быть временным каталогом в дереве кода, чтобы вы могли разработать HAL перед его публикацией.

Запуск службы

HAL предоставляет интерфейс IFoo , который должен выполнять асинхронные обратные вызовы к платформе через интерфейс IFooCallback . Интерфейс IFooCallback не зарегистрирован по имени в качестве обнаруживаемой службы; вместо этого IFoo должен содержать такой метод, как setFooCallback(IFooCallback x) .

Чтобы настроить IFooCallback из пакета android.hardware.foo версии 1.0, добавьте android.hardware.foo-V1.0-java в Android.mk . Код для запуска службы:

import android.hardware.foo.V1_0.IFoo;
import android.hardware.foo.V1_0.IFooCallback.Stub;
....
class FooCallback extends IFooCallback.Stub {
    // implement methods
}
....
// Get the service from which you will be receiving callbacks.
// This also starts the threadpool for your callback service.
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
....
// This must be a persistent instance variable, not local,
//   to avoid premature garbage collection.
FooCallback mFooCallback = new FooCallback();
....
// Do this once to create the callback service and tell the "foo-bar" service
server.setFooCallback(mFooCallback);

Расширения интерфейса

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

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

Вызывающий код, осведомленный о расширенном интерфейсе, может использовать Java-метод castFrom() для безопасного приведения базового интерфейса к расширенному интерфейсу:

IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IBetterFoo extendedService = IBetterFoo.castFrom(baseService);
if (extendedService != null) {
  // The service implements the extended interface.
} else {
  // The service implements only the base interface.
}