HIDL Java

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

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

На страницах этого раздела описывается интерфейс 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 , установленных на устройстве со стабильным Java API , доступно с помощью существующих 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 , и приложения, использующие эти (обязательно Priv приложения) должны иметь свои собственные отдельные копии. Модули на загрузочные классах , используя HIDL должны использовать неглубокие варианты этих библиотек Java и добавить jarjar_rules: ":framework-jarjar-rules" , чтобы их Android.bp использовать версии этих библиотек , которые существуют в загрузочном CLASSPATH.

Изменение исходного кода 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 . Пути в этом примере относительны; оборудование / интерфейсы могут быть временным каталогом в дереве кода, чтобы вы могли разработать HAL перед его публикацией.

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

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

Чтобы настроить IFooCallback от версии 1.0 android.hardware.foo пакет, добавьте 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 {
   ...
};

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

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.
}