RenderScript

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
  • 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 выбирается путь ЦП или графического процессора. Если выбран путь ЦП, 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.so
  • libm.so
  • libc.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 происходит в три этапа:

Сцена Сведения
Скомпилировать
  • Входной бит-код (.bc) для bcc должен быть в формате LLVM 3.2 и bcc обратно совместим с существующими (устаревшими) приложениями.
  • Однако метаданные в файле .bc могут измениться (могут появиться новые функции среды выполнения, например сеттеры и геттеры распределения, математические функции и т. д.). Часть функций времени выполнения находится в libclcore.bc, а часть – в LibRSDriver или эквивалентном файле поставщика.
  • Если вы добавляете новые функции времени выполнения или вносите критические изменения в метаданные, необходимо повысить уровень API бит-кода. Поскольку драйверы поставщиков не смогут использовать его, версию HAL также необходимо увеличить.
  • У поставщиков могут быть собственные компиляторы, но выводы и требования для bcc также применимы к ним.
Ссылка
  • Скомпилированный файл .o будет связан с драйвером поставщика, например libRSDriver_foo.so и libcompiler_rt.so. Путь CPU будет связан с libRSDriver.so.
  • Если для файла .o требуется новый API среды выполнения от libRSDriver_foo, необходимо обновить драйвер поставщика, чтобы он поддерживал этот API.
  • У некоторых поставщиков могут быть собственные связыватели, но аргументы в пользу 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. Вызовите системную функцию 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. Дополнительную информацию о прекращении поддержки можно найти в следующих ресурсах: