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

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 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» ).

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

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

Для графического процессора библиотека 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 libRS_internal.so в другом пространстве имён компоновщика, называемом rs .

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

Создание объекта 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 , если библиотека не может быть найдена/загружена из пространства имён sphal (что происходит всегда, поскольку пространство имён sphal не ищет в /system/lib/vndk-sp , где находится libRS_internal.so ). При такой конфигурации для перехода между пространствами имён достаточно простого вызова libRS_internal.so с помощью dlopen() .

Загрузить плагин скрытой копии

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

Для этого фреймворк RS использует разные пути поиска библиотек времени выполнения при выполнении ld.mc в зависимости от того, загружен ли сам фреймворк 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 см. в разделе Безопасность 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 Bitcode. Поскольку драйверы поставщика не смогут его использовать, необходимо также увеличить версию 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 . Информация о ресурсах, связанных с этим прекращением поддержки, включает следующее: