Рендерскрипт

RenderScript — это фреймворк для выполнения ресурсоемких вычислительных задач с высокой производительностью на Android. Он разработан для использования с параллельными вычислениями данных, хотя последовательные рабочие нагрузки также могут принести пользу. Среда выполнения RenderScript распараллеливает работу между процессорами, доступными на устройстве, такими как многоядерные ЦП и ГП, позволяя разработчикам сосредоточиться на выражении алгоритмов, а не на планировании работы. RenderScript особенно полезен для приложений, выполняющих обработку изображений, вычислительную фотографию или компьютерное зрение.

Устройства под управлением Android 8.0 и выше используют следующую инфраструктуру RenderScript и HAL-файлы поставщиков:

Рисунок 1. Код поставщика, связывающийся с внутренними библиотеками.

Отличия от RenderScript в Android 7.x и ниже включают в себя:

  • Два экземпляра внутренних библиотек RenderScript в процессе. Один набор предназначен для пути отката CPU и находится непосредственно в /system/lib ; другой набор предназначен для пути GPU и находится в /system/lib/vndk-sp .
  • Внутренние библиотеки RS в /system/lib собираются как часть платформы и обновляются при обновлении system.img . Однако библиотеки в /system/lib/vndk-sp собираются для поставщика и не обновляются при обновлении system.img (хотя их можно обновить для исправления безопасности, их ABI остается прежним).
  • Код поставщика (RS HAL, драйвер RS и bcc plugin ) связаны с внутренними библиотеками RenderScript, расположенными в /system/lib/vndk-sp . Они не могут быть связаны с библиотеками в /system/lib поскольку библиотеки в этом каталоге созданы для платформы и, следовательно, могут быть несовместимы с кодом поставщика (т. е. символы могут быть удалены). Это сделало бы OTA только для фреймворка невозможным.

Дизайн

В следующих разделах подробно описывается разработка RenderScript в Android 8.0 и выше.

Библиотеки RenderScript доступны поставщикам

В этом разделе перечислены библиотеки RenderScript (известные как Vendor NDK for Same-Process HALs или VNDK-SP), которые доступны для кода поставщика и с которыми можно выполнить линковку. Также подробно описаны дополнительные библиотеки, которые не связаны с RenderScript, но которые также предоставляются для кода поставщика.

Хотя следующий список библиотек может отличаться в разных версиях Android, он неизменен для конкретной версии Android; актуальный список доступных библиотек см. в файле /system/etc/ld.config.txt .

RenderScript библиотеки Библиотеки, не относящиеся к RenderScript
  • android.hardware.graphics.renderscript@1.0.so
  • libRS_internal.so
  • libRSCpuRef.so
  • libblas.so
  • libbcinfo.so
  • libcompiler_rt.so
  • libRSDriver.so
  • libc.so
  • libm.so
  • libdl.so
  • libstdc++.so
  • liblog.so
  • libnativewindow.so
  • libsync.so
  • libvndksupport.so
  • libbase.so
  • libc++.so
  • libcutils.so
  • libutils.so
  • libhardware.so
  • libhidlbase.so
  • libhidltransport.so
  • libhwbinder.so
  • liblzma.so
  • libz.so
  • libEGL.so
  • libGLESv1_CM.so
  • libGLESv2.so

Конфигурация пространства имен компоновщика

Ограничение на связывание, которое не позволяет использовать библиотеки, не входящие в VNDK-SP, кодом поставщика, применяется во время выполнения с использованием пространства имен компоновщика. (Подробности см. в презентации VNDK Design .)

На устройстве под управлением Android 8.0 и выше все однопроцессные HAL (SP-HAL), за исключением RenderScript, загружаются в пространство имен компоновщика sphal . RenderScript загружается в специфичное для RenderScript пространство имен rs , местоположение, которое обеспечивает немного более слабое соблюдение для библиотек RenderScript. Поскольку реализация RS должна загружать скомпилированный биткод, /data/*/*.so добавляется в путь пространства имен rs (другие SP-HAL не могут загружать библиотеки из раздела данных).

Кроме того, пространство имен rs допускает больше библиотек, чем предусмотрено другими пространствами имен. libmediandk.so и libft2.so доступны пространству имен rs , поскольку libRS_internal.so имеет внутреннюю зависимость от этих библиотек.

Рисунок 2. Конфигурация пространства имен для компоновщика.

Загрузить драйверы

Резервный путь ЦП

В зависимости от наличия бита RS_CONTEXT_LOW_LATENCY при создании контекста RS выбирается путь CPU или GPU. Когда выбирается путь CPU, libRS_internal.so (основная реализация фреймворка RS) напрямую dlopen из пространства имен компоновщика по умолчанию, где предоставляются платформенные версии библиотек RS.

Реализация RS HAL от поставщика вообще не используется, когда выбирается резервный путь ЦП, а объект RsContext создается с пустым mVendorDriverName . libRSDriver.so (по умолчанию) открывается с dlopen , а библиотека драйвера загружается из пространства имен default , поскольку вызывающая сторона ( libRS_internal.so ) также загружена в пространство имен default .

Рисунок 3. Путь восстановления ЦП.

Путь графического процессора

Для пути GPU libRS_internal.so загружается по-другому. Сначала libRS.so использует android.hardware.renderscript@1.0.so (и его базовый libhidltransport.so ) для загрузки android.hardware.renderscript@1.0-impl.so (реализация RS HAL от поставщика) в другое пространство имен компоновщика, называемое sphal . Затем RS HAL dlopen s libRS_internal.so в другое пространство имен компоновщика, называемое rs .

Поставщики могут предоставить свой собственный драйвер RS, установив флаг времени сборки OVERRIDE_RS_DRIVER , который встроен в реализацию RS HAL ( hardware/interfaces/renderscript/1.0/default/Context.cpp ). Это имя драйвера затем dlopen ed для контекста RS для пути GPU.

Создание объекта RsContext делегируется реализации RS HAL. HAL вызывает фреймворк RS, используя функцию rsContextCreateVendor() с именем драйвера для использования в качестве аргумента. Затем фреймворк RS загружает указанный драйвер при инициализации RsContext . В этом случае библиотека драйвера загружается в пространство имен rs , поскольку объект RsContext создается внутри пространства имен rs , а /vendor/lib находится в пути поиска пространства имен.

Рисунок 4. Резервный путь графического процессора.

При переходе из пространства имен default в пространство имен sphal libhidltransport.so использует функцию android_load_sphal_library() чтобы явно приказать динамическому компоновщику загрузить библиотеку -impl.so из пространства имен sphal .

При переходе из пространства имен sphal в пространство имен rs загрузка выполняется косвенно с помощью следующей строки в /system/etc/ld.config.txt :

namespace.sphal.link.rs.shared_libs = libRS_internal.so

Эта строка указывает, что динамический компоновщик должен загрузить libRS_internal.so из пространства имен rs , когда lib не может быть найдена/загружена из пространства имен sphal (что всегда так, поскольку пространство имен sphal не ищет /system/lib/vndk-sp , где находится libRS_internal.so ). При такой конфигурации простого вызова dlopen() для libRS_internal.so достаточно для перехода пространства имен.

Загрузить плагин BCC

bcc plugin — это библиотека, предоставляемая поставщиком, загружаемая в компилятор bcc . Поскольку bcc — это системный процесс в каталоге /system/bin , библиотеку bcc plugin можно считать SP-HAL (т. е. HAL поставщика, который может быть напрямую загружен в системный процесс без привязки). Как SP-HAL, библиотека bcc-plugin :

  • Невозможно выполнить компоновку с библиотеками, предназначенными только для фреймворков, такими как libLLVM.so .
  • Возможна связь только с библиотеками VNDK-SP, доступными поставщику.

Это ограничение обеспечивается загрузкой bcc plugin в пространство имен sphal с помощью функции android_sphal_load_library() . В предыдущих версиях Android имя плагина указывалось с помощью опции -load , а библиотека загружалась с помощью простого dlopen() с помощью libLLVM.so . В Android 8.0 и выше это указывается в опции -plugin , а библиотека загружается непосредственно самим bcc . Эта опция включает неспецифичный для Android путь к проекту LLVM с открытым исходным кодом.

Рисунок 5. Загрузка плагина bcc, Android 7.x и ниже.



Рисунок 6. Загрузка плагина bcc, Android 8.0 и выше.

Пути поиска для ld.mc

При выполнении ld.mc некоторые библиотеки времени выполнения RS передаются в качестве входных данных для компоновщика. Бит-код RS из приложения связывается с библиотеками времени выполнения, и когда преобразованный бит-код загружается в процесс приложения, библиотеки времени выполнения снова динамически связываются с преобразованным бит-кодом.

Библиотеки времени выполнения включают в себя:

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • Драйвер RS ( libRSDriver.so или OVERRIDE_RS_DRIVER )

При загрузке скомпилированного биткода в процесс приложения предоставьте точно такую ​​же библиотеку, которая использовалась ld.mc В противном случае скомпилированный биткод может не найти символ, который был доступен при его компоновке.

Для этого фреймворк RS использует различные пути поиска для библиотек времени выполнения при выполнении ld.mc в зависимости от того, загружен ли сам фреймворк RS из /system/lib или из /system/lib/vndk-sp . Это можно определить, прочитав адрес произвольного символа библиотеки RS Framework и используя dladdr() для получения пути к файлу, сопоставленного с адресом.

Политика SELinux

В результате изменений политики SELinux в Android 8.0 и выше необходимо соблюдать определенные правила (применяемые с помощью neverallows ) при маркировке дополнительных файлов в разделе vendor :

  • vendor_file должен быть меткой по умолчанию для всех файлов в разделе vendor . Политика платформы требует этого для доступа к реализациям HAL passthrough.
  • Все новые exec_types добавленные в раздел vendor через SEPolicy поставщика, должны иметь атрибут vendor_file_type . Это обеспечивается через neverallows .
  • Чтобы избежать конфликтов с будущими обновлениями платформы/фреймворка, не маркируйте файлы, отличные от exec_types в разделе vendor .
  • Все зависимости библиотек для тех же процессов HAL, которые идентифицированы AOSP, должны быть помечены как same_process_hal_file .

Подробную информацию о политике SELinux см. в разделе Безопасность Linux в Android .

Совместимость ABI для биткода

Если не будут добавлены новые API, что означает отсутствие повышения версии HAL, фреймворки RS продолжат использовать существующий драйвер GPU (HAL 1.0).

Для незначительных изменений HAL (HAL 1.1), не влияющих на биткод, фреймворки должны вернуться к использованию CPU для этих новых API и продолжать использовать драйвер GPU (HAL 1.0) в других местах.

В случае серьезных изменений HAL (HAL 2.0), влияющих на компиляцию/связывание биткода, фреймворки RS должны не загружать предоставленные поставщиком драйверы графического процессора, а вместо этого использовать путь ЦП или Vulkan для ускорения.

Использование биткода RenderScript происходит в три этапа:

Этап Подробности
Компилировать
  • Входной битовый код (.bc) для bcc должен быть в формате битового кода LLVM 3.2 а bcc должен быть обратно совместим с существующими (устаревшими) приложениями.
  • Однако метаданные в .bc могут измениться (могут появиться новые функции времени выполнения, например, установщики ∓ геттеры распределения, математические функции и т. д.). Часть функций времени выполнения находится в libclcore.bc , часть — в LibRSDriver или эквиваленте поставщика.
  • Новые функции времени выполнения или критические изменения метаданных требуют увеличения уровня API биткода. Поскольку драйверы поставщиков не смогут его использовать, версию HAL также необходимо увеличить.
  • Поставщики могут иметь собственные компиляторы, но выводы/требования для bcc применимы и к этим компиляторам.
Связь
  • Скомпилированный .o будет связан с драйвером поставщика, например, libRSDriver_foo.so и libcompiler_rt.so . Путь ЦП будет связан с libRSDriver.so .
  • Если .o требует нового API среды выполнения от libRSDriver_foo , драйвер поставщика необходимо обновить для его поддержки.
  • У некоторых поставщиков могут быть свои собственные компоновщики, но аргумент в пользу ld.mc применим и к ним.
Нагрузка
  • libRSCpuRef загружает общий объект. Если в этом интерфейсе есть изменения, необходимо повышение версии HAL.
  • Поставщикам придется либо полагаться на libRSCpuRef для загрузки общего объекта, либо реализовывать свой собственный.

В дополнение к HAL, интерфейсами также являются API среды выполнения и экспортированные символы. Ни один из интерфейсов не изменился с Android 7.0 (API 24), и нет никаких непосредственных планов изменить его в Android 8.0 и далее. Однако, если интерфейс изменится, версия HAL также увеличится.

Реализации поставщиков

Для корректной работы драйвера графического процессора в Android 8.0 и выше требуются некоторые изменения в драйвере графического процессора.

Модули драйверов

  • Модули драйверов не должны зависеть от каких-либо системных библиотек, отсутствующих в списке .
  • Драйвер должен предоставить свой собственный android.hardware.renderscript@1.0-impl_{NAME} или объявить реализацию по умолчанию android.hardware.renderscript@1.0-impl в качестве своей зависимости.
  • Реализация ЦП libRSDriver.so является хорошим примером того, как удалить зависимости, не относящиеся к VNDK-SP.

Компилятор биткода

Скомпилировать биткод RenderScript для драйвера поставщика можно двумя способами:

  1. Вызовите специфичный для поставщика компилятор RenderScript в /vendor/bin/ (предпочтительный метод компиляции GPU). Подобно другим модулям драйвера, двоичный файл компилятора поставщика не может зависеть от какой-либо системной библиотеки, которая не входит в список библиотек RenderScript, доступных поставщикам .
  2. Вызовите system bcc: /system/bin/bcc с помощью bcc plugin , предоставленного поставщиком; этот плагин не может зависеть от какой-либо системной библиотеки, которая не входит в список библиотек RenderScript, доступных поставщикам .

Если bcc plugin необходимо вмешаться в компиляцию ЦП, а его зависимость от libLLVM.so нельзя легко удалить, поставщик должен скопировать bcc (и все зависимости, не относящиеся к LL-NDK, включая libLLVM.so , libbcc.so ) в раздел /vendor .

Кроме того, поставщикам необходимо внести следующие изменения:

Рисунок 7. Изменения в драйвере поставщика.

  1. Скопируйте libclcore.bc в раздел /vendor . Это гарантирует синхронизацию libclcore.bc , libLLVM.so и libbcc.so .
  2. Измените путь к исполняемому файлу bcc , установив RsdCpuScriptImpl::BCC_EXE_PATH из реализации RS HAL.

Политика SELinux

Политика SELinux влияет как на драйвер, так и на исполняемые файлы компилятора. Все модули драйвера должны быть помечены как same_process_hal_file в file_contexts устройства. Например:

/vendor/lib(64)?/libRSDriver_EXAMPLE\.so     u:object_r:same_process_hal_file:s0

Исполняемый файл компилятора должен иметь возможность вызываться процессом приложения, как и копия поставщика bcc ( /vendor/bin/bcc ). Например:

device/vendor_foo/device_bar/sepolicy/file_contexts:
/vendor/bin/bcc                    u:object_r:same_process_hal_file:s0

Устаревшие устройства

Устаревшими считаются устройства, которые удовлетворяют следующим условиям:

  1. PRODUCT_SHIPPING_API_LEVEL ниже 26.
  2. PRODUCT_FULL_TREBLE_OVERRIDE не определен.

Для устаревших устройств ограничения не применяются при обновлении до Android 8.0 и выше, то есть драйверы могут продолжать ссылаться на библиотеки в /system/lib[64] . Однако из-за изменения архитектуры, связанного с OVERRIDE_RS_DRIVER , android.hardware.renderscript@1.0-impl должен быть установлен в раздел /vendor ; в противном случае среда выполнения RenderScript будет откатываться к пути ЦП.

Информацию о мотивации устаревания Renderscript см. в блоге разработчиков Android: Android GPU Compute Going Forward . Информация о ресурсах для этого устаревания включает следующее: