Динамический запуск сервисов AIDL

В Android 11 и более поздних версиях нативные сервисы AIDL, работающие в системном разделе, можно запускать и останавливать динамически по мере необходимости. Динамические сервисы запускаются при первом запросе и автоматически останавливаются, когда перестают использоваться.

Сервисы, которые могут работать динамически

Эта функция доступна только для встроенных сервисов, жизненным циклом которых можно управлять с помощью init и servicemanager. Сервисы в пакетах приложений не поддерживаются. Вместо них следует использовать связанные сервисы.

Динамическое завершение работы останавливает процесс, в котором выполняется служба. Если в одном процессе существует несколько сервисов, все они должны быть зарегистрированы как динамические, чтобы быть совместимыми с этой функцией. После этого процесс будет завершен, когда все сервисы станут неиспользуемыми.

Как настроить файл инициализации .rc сервиса

Чтобы запустить сервис динамически, добавьте следующие параметры в файл init .rc сервиса после строки service <name> <cmd>.

interface aidl serviceName
disabled
oneshot

Эти параметры выполняют следующие действия:

  • interface aidl serviceName: позволяет servicemanager найти сервис. Если сервис использует несколько интерфейсов, укажите каждый из них на отдельной строке. Эти имена должны быть именно такими, как ожидает servicemanager, и могут отличаться от названия процесса.
  • disabled – запрещает автоматический запуск сервиса при загрузке.
  • oneshot – запрещает автоматический перезапуск службы после каждой остановки.

Подробную информацию можно найти в файле Readme, посвященном языку инициализации Android, в AOSP.

Примеры:

Как зарегистрировать сервис

Каждый сервис создается и регистрируется в servicemanager. Регистрация часто происходит в файле с названием main.cpp, но реализация может быть разной. Обычно регистрация выглядит следующим образом:

using android::defaultServiceManager;

defaultServiceManager()->addService(serviceName, service);

Иногда регистрация абстрагируется с помощью BinderService::publish или BinderService::instantiate, которые вызывают указанный выше код.

Чтобы зарегистрировать сервис как динамический, замените его код регистрации следующим:

#include <binder/LazyServiceRegistrar.h>

using android::binder::LazyServiceRegistrar;

auto lazyRegistrar = LazyServiceRegistrar::getInstance();
lazyRegistrar.registerService(service, serviceName);

servicemanager взаимодействует с LazyServiceRegistrar, чтобы завершить работу сервисов на основе количества ссылок.

Примеры:

Как настроить клиентов сервиса AIDL

Как получить услугу

Чтобы получить отложенный сервис, его нужно запустить, а затем извлечь. Вызов getService в менеджере сервисов запустит сервис, но обычно вам нужно получить сервис, как только он станет доступен, и следует использовать варианты waitForService. Инструкции по их использованию можно найти в документации по конкретным серверным компонентам.

Как отменить связь с сервисом

Динамическое завершение работы основано на подсчете ссылок, поэтому клиенты не должны удерживать сервис, когда он не используется.

Примеры:

Как временно отключить завершение работы

Если вы хотите, чтобы сервис работал независимо, пока не будут выполнены определенные задачи, а затем переключился на динамическое поведение, вы можете использовать LazyServiceRegistrar::forcePersist, чтобы включить или отключить динамическое завершение работы. Если этот метод вызывается на стороне сервера, он должен вызываться до registerService.

Пример: apexservice.