Используйте связующее IPC

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

Изменения в драйвере подшивщика

Начиная с Android 8, платформа Android и HAL теперь взаимодействуют друг с другом с помощью связующего. Поскольку такая связь значительно увеличивает трафик подшивок, Android 8 включает в себя несколько улучшений, призванных обеспечить высокую скорость 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 АНДРОИД: связыватель: не проверять приоритетные разрешения при восстановлении.
  • Общий-4,4
    76b376eac7a2 ANDROID: связыватель: не проверять разрешения Prio при восстановлении.
  • Общий-4,9
    ecd972d4f9b5 ANDROID: связыватель: не проверять разрешения Prio при восстановлении.

Работа с подшивкой IPC

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

вндбиндер

Android 8 поддерживает новый домен связывания для использования службами поставщиков, доступ к которому осуществляется с помощью /dev/vndbinder вместо /dev/binder . С добавлением /dev/vndbinder Android теперь имеет следующие три домена 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 , которая открывает драйвер связующего. Добавление метода для ::android::ProcessState() выбирает драйвер связывателя для libbinder . Процессы поставщика должны вызывать этот метод перед вызовом ProcessState, IPCThreadState или вообще перед выполнением каких-либо вызовов связывания. Для использования поместите следующий вызов после main() процесса поставщика (клиента и сервера):

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

вндсервисменеджер

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

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

Двоичный файл 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, которым необходимо обмениваться данными через связыватель, может оставаться на месте и не требует переименования.

Чтобы выполнить требование 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 . Пример:

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;