RenderScript – это фреймворк для выполнения ресурсоемких задач на устройствах Android с высокой производительностью. Он предназначен для использования с параллельными вычислениями, но также может быть полезен при последовательных нагрузках. Среда выполнения RenderScript распределяет задачи между доступными процессорами устройства, например многоядерными ЦП и графическими процессорами. Это позволяет разработчикам сосредоточиться на алгоритмах, а не на планировании задач. RenderScript особенно полезен для приложений, которые обрабатывают изображения, выполняют вычислительную фотографию или машинное зрение.
На устройствах с Android 8.0 и более поздних версий используются следующие фреймворки RenderScript и HAL от поставщиков:
Рисунок 1. Код поставщика, связанный с внутренними библиотеками.
Отличия от RenderScript в Android 7.x и более ранних версиях:
- Два экземпляра внутренних библиотек RenderScript в одном процессе. Один набор предназначен для резервного пути ЦП и находится непосредственно в
/system/lib, а другой – для пути графического процессора и находится в/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 для HAL, работающих в том же процессе, или VNDK-SP), которые доступны для кода поставщика и с которыми можно установить связь. В нем также подробно описаны дополнительные библиотеки, которые не связаны с RenderScript, но также предоставляются коду поставщика.
Список библиотек может различаться в разных версиях Android, но в рамках одной версии он не меняется. Актуальный список доступных библиотек можно найти в /system/etc/ld.config.txt.
| Библиотеки RenderScript | Библиотеки, не относящиеся к RenderScript |
|---|---|
|
|
Настройка пространства имен тега связывания
Ограничение на связывание, запрещающее использование библиотек, не входящих в 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 выбирается путь ЦП или графического процессора. Если выбран путь ЦП, libRS_internal.so (основная реализация фреймворка RenderScript) напрямую dlopenется из пространства имен компоновщика по умолчанию, где предоставляются библиотеки RenderScript для платформы.
Реализация RS HAL от поставщика не используется, если выбран резервный путь ЦП, а объект RsContext создается с нулевым значением mVendorDriverName. libRSDriver.so (по умолчанию) dlopen, а библиотека драйвера загружается из пространства имен default, поскольку вызывающий объект (libRS_internal.so) также загружается в пространство имен default.
Рисунок 3. Резервный путь ЦП.
Путь графического процессора
При использовании графического процессора libRS_internal.so загружается иначе.
Сначала libRS.so использует android.hardware.renderscript@1.0.so (и его базовый libhidltransport.so), чтобы загрузить android.hardware.renderscript@1.0-impl.so (реализацию поставщика RS HAL) в другое пространство имен компоновщика под названием sphal. Затем HAL RS dlopen libRS_internal.so в другом пространстве имен компоновщика, которое называется rs.
Поставщики могут предоставить собственный драйвер RS, задав флаг времени сборки OVERRIDE_RS_DRIVER, который встроен в реализацию HAL RS hardware/interfaces/renderscript/1.0/default/Context.cpp. Затем имя этого драйвера dlopenется для контекста RS для пути GPU.
Создание объекта RsContext делегируется реализации HAL RS. HAL обращается к фреймворку RS с помощью функции rsContextCreateVendor(), используя название драйвера в качестве аргумента. Затем при инициализации RsContext фреймворк RS загружает указанный драйвер. В этом случае библиотека драйверов загружается в пространство имен 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 поставщика, который можно напрямую загрузить в системный процесс без использования Binder). Как 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. Этот параметр позволяет указать путь к проекту LLVM с открытым исходным кодом, не относящийся к Android.
Рисунок 5. Загрузка плагина bcc, Android 7.x и более ранние версии.
Рисунок 6. Загрузка плагина bcc, Android 8.0 и более поздних версий.
Пути поиска для ld.mc
При выполнении ld.mc некоторые библиотеки времени выполнения RS передаются компоновщику в качестве входных данных. Бит-код RS из приложения связывается с библиотеками среды выполнения, а когда преобразованный бит-код загружается в процесс приложения, библиотеки среды выполнения снова динамически связываются с преобразованным бит-кодом.
Библиотеки среды выполнения:
libcompiler_rt.solibm.solibc.so- Драйвер RS (
libRSDriver.soилиOVERRIDE_RS_DRIVER)
При загрузке скомпилированного бит-кода в процесс приложения укажите ту же библиотеку, которая использовалась в ld.mc. В противном случае скомпилированный бит-код может не найти символ, который был доступен при его связывании.
Для этого при выполнении ld.mc фреймворк RS использует разные пути поиска библиотек времени выполнения в зависимости от того, загружен ли сам фреймворк RS из /system/lib или из /system/lib/vndk-sp.
Это можно определить, прочитав адрес произвольного символа библиотеки фреймворка RS и используя dladdr(), чтобы получить путь к файлу, сопоставленный с адресом.
Правила SELinux
В результате изменений в политике SELinux в Android 8.0 и более поздних версий при присвоении ярлыков дополнительным файлам в разделе vendor необходимо соблюдать определенные правила (принудительно применяемые с помощью neverallows):
vendor_fileдолжен быть ярлыком по умолчанию для всех файлов в разделеvendor. Это необходимо в соответствии с требованиями правил платформы для доступа к реализациям HAL сквозной передачи.- Все новые объекты
exec_types, добавленные в разделvendorс помощью правил SEPolicy поставщика, должны иметь атрибутvendor_file_type. Это правило применяется с помощьюneverallows. - Чтобы избежать конфликтов с будущими обновлениями платформы или фреймворка, не присваивайте ярлыки файлам, отличным от
exec_types, в разделеvendor. - Все зависимости библиотек для HAL, которые AOSP определяет как работающие в одном процессе, должны быть помечены как
same_process_hal_file.
Подробнее о политике SELinux…
Совместимость ABI с бит-кодом
Если новые API не добавлены, а значит, версия HAL не изменилась, фреймворки RenderScript будут использовать существующий драйвер GPU (HAL 1.0).
Если изменения в HAL незначительны (HAL 1.1) и не влияют на биткод, фреймворки должны использовать ЦП для новых API и драйвер GPU (HAL 1.0) для остальных функций.
При значительных изменениях HAL (HAL 2.0), влияющих на компиляцию/связывание битового кода, фреймворки RenderScript должны отказаться от загрузки предоставленных поставщиком драйверов GPU и вместо этого использовать для ускорения CPU или Vulkan.
Использование бит-кода RenderScript происходит в три этапа:
| Сцена | Сведения |
|---|---|
| Скомпилировать |
|
| Ссылка |
|
| Загрузить |
|
Помимо 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 для драйвера поставщика можно двумя способами:
- Вызовите компилятор RenderScript от поставщика в
/vendor/bin/(предпочтительный метод компиляции на GPU). Как и другие модули драйверов, двоичный файл компилятора поставщика не может зависеть от системной библиотеки, которой нет в списке библиотек RenderScript, доступных поставщикам. - Вызовите системную функцию bcc:
/system/bin/bcc, используя предоставленный поставщикомbcc plugin. Этот плагин не может зависеть от системной библиотеки, которой нет в списке библиотек RenderScript, доступных поставщикам.
Если поставщику bcc plugin необходимо вмешаться в компиляцию ЦП и зависимость от libLLVM.so нельзя легко удалить, поставщик должен скопировать bcc (и все зависимости, не относящиеся к LL-NDK, включая libLLVM.so и libbcc.so) в раздел /vendor.
Кроме того, поставщикам необходимо внести следующие изменения:
Рисунок 7. Изменения в драйвере поставщика.
- Скопировать раздел
libclcore.bcв раздел/vendor. Это обеспечит синхронизациюlibclcore.bc,libLLVM.soиlibbcc.so. - Измените путь к исполняемому файлу
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
Устаревшие устройства
Устройства устаревшей версии должны соответствовать следующим условиям:
- Значение PRODUCT_SHIPPING_API_LEVEL ниже 26.
- 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. Дополнительную информацию о прекращении поддержки можно найти в следующих ресурсах:
- Переход с RenderScript
- Пример RenderScriptMigration
- Файл README для Intrinsics Replacement Toolkit
- Intrinsics ReplacementToolkit.kt