Использование Binder IPC

На этой странице описаны изменения в драйвере связывания в Android 8, приведены подробные сведения об использовании IPC связывания и перечислены необходимые политики SELinux.

Изменения в драйвере связующего

Начиная с Android 8, платформа Android и HAL теперь взаимодействуют друг с другом с помощью связывателя. Поскольку это взаимодействие резко увеличивает трафик связывателей, Android 8 включает в себя несколько улучшений, предназначенных для быстрой работы Binder IPC. Поставщики SoC и OEM-производители должны объединяться напрямую из соответствующих веток android-4.4, android-4.9 и более поздних версий ядра / общего проекта.

Множественные домены связывания (контексты)

Common-4.4 и выше, включая апстрим

Чтобы четко разделить трафик связывателя между кодом платформы (независимым от устройства) и кодом поставщика (зависящим от устройства), в Android 8 была введена концепция контекста связывания . Каждый контекст связывателя имеет свой собственный узел устройства и свой собственный диспетчер контекста (службы). Вы можете получить доступ к диспетчеру контекста только через узел устройства, которому он принадлежит, и при передаче узла связывания через определенный контекст он доступен из того же контекста только другим процессом, таким образом полностью изолируя домены друг от друга. Подробнее об использовании см. Vndbinder и vndservicemanager .

Разбросать

Common-4.4 и выше, включая апстрим

В предыдущих выпусках Android каждый фрагмент данных в вызове связывателя копировался трижды:

  • Один раз для сериализации в Parcel в вызывающем процессе
  • Попав в драйвер ядра, чтобы скопировать Parcel в целевой процесс
  • Один раз для десериализации Parcel в целевом процессе

Android 8 использует оптимизацию разброса-сбора, чтобы уменьшить количество копий с 3 до 1. Вместо того, чтобы сначала сериализовать данные в Parcel , данные остаются в исходной структуре и структуре памяти, и драйвер немедленно копирует их в целевой процесс. После того, как данные находятся в целевом процессе, структура и расположение памяти остаются прежними, и данные можно читать, не требуя повторной копии.

Мелкозернистая блокировка

Common-4.4 и выше, включая апстрим

В предыдущих выпусках Android драйвер связывания использовал глобальную блокировку для защиты от одновременного доступа к критически важным структурам данных. Хотя конкуренция за блокировку была минимальной, основная проблема заключалась в том, что если поток с низким приоритетом получил блокировку, а затем был вытеснен, он мог серьезно задержать потоки с более высоким приоритетом, которым необходимо получить ту же блокировку. Это вызвало рывки платформы.

Первоначальные попытки решить эту проблему включали отключение приоритетного обслуживания при удержании глобальной блокировки. Однако это было больше похоже на взлом, чем на истинное решение, и в конечном итоге оно было отклонено апстримом и отброшено. Последующие попытки были направлены на то, чтобы сделать блокировку более детальной, версия которой работает на устройствах Pixel с января 2017 года. Хотя большинство этих изменений были обнародованы, в последующих версиях были внесены существенные улучшения.

После выявления небольших проблем в реализации детальной блокировки мы разработали улучшенное решение с другой архитектурой блокировки и представили изменения во всех распространенных ветвях ядра. Мы продолжаем тестировать эту реализацию на большом количестве различных устройств; поскольку нам неизвестны нерешенные проблемы, это рекомендуемая реализация для устройств, поставляемых с Android 8.

Наследование приоритета в реальном времени

Common-4.4 и common-4.9 (скоро появится апстрим)

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

В дополнение к наследованию приоритета на уровне транзакции наследование приоритета узла позволяет узлу (объекту службы связывания) указывать минимальный приоритет, при котором должны выполняться вызовы этого узла. Предыдущие версии Android уже поддерживали наследование приоритета узлов с хорошими значениями, но в Android 8 добавлена ​​поддержка наследования узлов политик планирования в реальном времени.

Изменения в пользовательском пространстве

Android 8 включает все изменения пользовательского пространства, необходимые для работы с текущим драйвером связывателя в общем ядре, за одним исключением: исходная реализация для отключения наследования приоритета в реальном времени для /dev/binder использовала ioctl . Последующая разработка переключила управление наследованием приоритета на более детализированный метод, который предназначен для режима связывания (а не для контекста). Таким образом, ioctl не находится в общей ветке Android, а вместо этого представлен в наших общих ядрах .

В результате этого изменения наследование приоритета в реальном времени отключено по умолчанию для каждого узла. Команда по производительности Android сочла полезным включить наследование приоритетов в реальном времени для всех узлов в домене hwbinder . Чтобы добиться того же эффекта, выберите это изменение в пользовательском пространстве.

SHA для общих ядер

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

  • Обычный-3.18
    cc8b90c121de ANDROID: binder: не проверять приоритетные разрешения при восстановлении.
  • Обычный-4.4
    76b376eac7a2 ANDROID: binder: не проверять приоритетные разрешения при восстановлении.
  • Обычный-4.9
    ecd972d4f9b5 ANDROID: binder: не проверять приоритетные разрешения при восстановлении.

Использование связующего IPC

Исторически сложилось так, что в процессах поставщиков для связи использовалось межпроцессное взаимодействие связывателей (IPC). В Android 8 узел устройства /dev/binder становится эксклюзивным для процессов инфраструктуры, что означает, что процессы поставщика больше не имеют к нему доступа. Процессы поставщика могут получить доступ к /dev/hwbinder , но должны преобразовать свои интерфейсы AIDL для использования HIDL. Для поставщиков, которые хотят продолжать использовать интерфейсы AIDL между процессами поставщиков, Android поддерживает связывание IPC, как описано ниже.

vndbinder

Android 8 поддерживает новый домен Связующее для использования услуг поставщика, доступ , используя /dev/vndbinder вместо /dev/binder . С добавлением /dev/vndbinder Android теперь есть следующие три домена IPC:

Домен IPC Описание
/dev/binder IPC между процессами платформы / приложения с интерфейсами AIDL
/dev/hwbinder IPC между процессами платформы / поставщика с интерфейсами HIDL
IPC между процессами поставщиков с интерфейсами HIDL
/dev/vndbinder IPC между вендорами / вендорными процессами с интерфейсами AIDL

Для /dev/vndbinder убедитесь, что для элемента конфигурации ядра CONFIG_ANDROID_BINDER_DEVICES установлено значение "binder,hwbinder,vndbinder" (это значение по умолчанию в общих деревьях ядра Android).

Обычно процессы поставщика не открывают драйвер связывания напрямую, а вместо этого связываются с библиотекой пользовательского пространства libbinder , которая открывает драйвер libbinder . Добавление метода для ::android::ProcessState() выбирает драйвер libbinder для libbinder . Процессы поставщика должны вызывать этот метод перед вызовом ProcessState, IPCThreadState или перед выполнением каких-либо вызовов связующего в целом. Для использования поместите следующий вызов после main() процесса поставщика (клиента и сервера):

ProcessState::initWithDriver("/dev/vndbinder");

vndservicemanager

Ранее службы связывания регистрировались в servicemanager , откуда они могли быть получены другими процессами. В Android 8 servicemanager теперь используется исключительно процессами платформы и приложений, и процессы поставщика больше не могут получить к нему доступ.

Однако услуги поставщиков могут теперь использовать vndservicemanager , новый экземпляр servicemanager , который использует /dev/vndbinder вместо /dev/binder и который строится из тех же источников, рамочный servicemanager . Для vndservicemanager с vndservicemanager процессам поставщика не нужно вносить изменения; когда процесс поставщика открывает / dev/vndbinder , поиск службы автоматически переходит в vndservicemanager .

vndservicemanager файл vndservicemanager включен в make- vndservicemanager устройства Android по умолчанию.

Политика SELinux

Процессам поставщика, которые хотят использовать функциональные возможности связывания для взаимодействия друг с другом, необходимо следующее:

  1. Доступ к /dev/vndbinder .
  2. Binder {transfer, call} перехватывает vndservicemanager .
  3. binder_call(A, B) для любого домена поставщика A, который хочет позвонить в домен поставщика B через интерфейс связующего поставщика.
  4. Разрешение на {add, find} сервисы в vndservicemanager .

Для выполнения требований 1 и 2 используйте vndbinder_use() :

vndbinder_use(some_vendor_process_domain);

Чтобы выполнить требование 3, binder_call(A, B) для процессов поставщика A и B, которым необходимо binder_call(A, B) через binder_call(A, B) может оставаться на месте и не требует переименования.

Чтобы выполнить требование 4, вы должны внести изменения в способ обработки имен служб, меток служб и правил.

Дополнительные сведения о SELinux см. В разделе Linux с повышенной безопасностью в Android . Дополнительные сведения о SELinux в Android 8.0 см. В разделе SELinux для Android 8.0 .

Названия сервисов

Ранее поставщик обрабатывал зарегистрированные имена служб в файле service_contexts и добавлял соответствующие правила для доступа к этому файлу. Пример файла service_contexts с device/google/marlin/sepolicy :

AtCmdFwd                              u:object_r:atfwd_service:s0
cneservice                            u:object_r:cne_service:s0
qti.ims.connectionmanagerservice      u:object_r:imscm_service:s0
rcs                                   u:object_r:radio_service:s0
uce                                   u:object_r:uce_service:s0
vendor.qcom.PeripheralManager         u:object_r:per_mgr_service:s0

В Android 8 вместо этого vndservicemanager загружает файл vndservice_contexts . Сервисы поставщика, мигрирующие в vndservicemanager (и которые уже находятся в старом файле service_contexts ), должны быть добавлены в новый файл vndservice_contexts .

Сервисные этикетки

Ранее метки служб, такие как u:object_r:atfwd_service:s0 были определены в файле service.te . Пример:

type atfwd_service,      service_manager_type;

В Android 8 необходимо изменить тип на vndservice_manager_type и переместить правило в файл vndservice.te . Пример:

type atfwd_service,      vndservice_manager_type;

Правила Servicemanager

Ранее правила предоставляли доменам доступ для добавления или поиска сервисов из servicemanager . Пример:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;

В Android 8 такие правила могут оставаться на месте и использовать один и тот же класс. Пример:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;