В 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-файлов, установленных на устройстве, со стабильными 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, чтобы использовать версию этих библиотек, которая существует в пути загрузки классов.
Как изменить источник 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, выполнив следующие действия:
- Определите интерфейс в HIDL.
- Откройте
/tmp/android/hardware/foo/IFooCallback.javaв качестве справочного материала. - Создайте новый модуль для реализации на Java.
- Изучите абстрактный класс
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. }