Renderscript

RenderScript es un marco para ejecutar tareas computacionalmente intensivas con alto rendimiento en Android. Está diseñado para usarse con computación de datos en paralelo, aunque las cargas de trabajo en serie también pueden beneficiarse. El tiempo de ejecución de RenderScript paraleliza el trabajo entre los procesadores disponibles en un dispositivo, como CPU y GPU de múltiples núcleos, lo que permite a los desarrolladores centrarse en expresar algoritmos en lugar de programar el trabajo. RenderScript es especialmente útil para aplicaciones que realizan procesamiento de imágenes, fotografía computacional o visión por computadora.

Los dispositivos que ejecutan Android 8.0 y versiones posteriores utilizan el siguiente marco de RenderScript y HAL de proveedores:

Figura 1. Código de proveedor vinculado a bibliotecas internas

Las diferencias con RenderScript en Android 7.x y versiones anteriores incluyen:

  • Dos instancias de bibliotecas internas de RenderScript en un proceso. Un conjunto es para la ruta alternativa de la CPU y se encuentra directamente en /system/lib ; el otro conjunto es para la ruta de la GPU y proviene de /system/lib/vndk-sp .
  • Las bibliotecas internas de RS en /system/lib se crean como parte de la plataforma y se actualizan a medida que se actualiza system.img . Sin embargo, las bibliotecas en /system/lib/vndk-sp están creadas para el proveedor y no se actualizan cuando se actualiza system.img (si bien se pueden actualizar para una solución de seguridad, su ABI sigue siendo la misma).
  • El código del proveedor (RS HAL, controlador RS y el bcc plugin ) están vinculados a las bibliotecas internas de RenderScript ubicadas en /system/lib/vndk-sp . No pueden vincularse con bibliotecas en /system/lib porque las bibliotecas en ese directorio están creadas para la plataforma y, por lo tanto, pueden no ser compatibles con el código del proveedor (es decir, los símbolos pueden eliminarse). Hacerlo haría imposible una OTA basada únicamente en el marco.

Diseño

Las siguientes secciones detallan el diseño de RenderScript en Android 8.0 y superior.

Bibliotecas de RenderScript disponibles para proveedores

Esta sección enumera las bibliotecas de RenderScript (conocidas como NDK de proveedor para HAL del mismo proceso o VNDK-SP) que están disponibles para el código de proveedor y con las que se pueden vincular. También detalla bibliotecas adicionales que no están relacionadas con RenderScript pero que también se proporcionan con el código del proveedor.

Si bien la siguiente lista de bibliotecas puede diferir entre las versiones de Android, es inmutable para una versión específica de Android; Para obtener una lista actualizada de las bibliotecas disponibles, consulte /system/etc/ld.config.txt .

Bibliotecas de RenderScript Bibliotecas que no son de 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

Configuración del espacio de nombres del vinculador

La restricción de vinculación que evita que el código del proveedor utilice bibliotecas que no están en VNDK-SP se aplica en tiempo de ejecución mediante el espacio de nombres del vinculador. (Para obtener más detalles, consulte la presentación de Diseño VNDK ).

En un dispositivo con Android 8.0 y superior, todos los HAL del mismo proceso (SP-HAL), excepto RenderScript, se cargan dentro del espacio de nombres del vinculador sphal . RenderScript se carga en el espacio de nombres específico de RenderScript rs , una ubicación que permite una aplicación ligeramente más flexible para las bibliotecas de RenderScript. Debido a que la implementación de RS necesita cargar el código de bits compilado, /data/*/*.so se agrega a la ruta del espacio de nombres rs (otros SP-HAL no pueden cargar bibliotecas desde la partición de datos).

Además, el espacio de nombres rs permite más bibliotecas que las proporcionadas por otros espacios de nombres. libmediandk.so y libft2.so están expuestos al espacio de nombres rs porque libRS_internal.so tiene una dependencia interna de estas bibliotecas.

Figura 2. Configuración del espacio de nombres para el vinculador

Cargando controladores

Ruta de respaldo de la CPU

Dependiendo de la existencia del bit RS_CONTEXT_LOW_LATENCY al crear un contexto RS, se selecciona la ruta de CPU o GPU. Cuando se selecciona la ruta de la CPU, libRS_internal.so (la implementación principal del marco RS) se dlopen directamente desde el espacio de nombres del vinculador predeterminado donde se proporciona la versión de plataforma de las bibliotecas RS.

La implementación RS HAL del proveedor no se utiliza en absoluto cuando se toma la ruta alternativa de la CPU y se crea un objeto RsContext con mVendorDriverName nulo. libRSDriver.so está (de forma predeterminada) dlopen ed y la biblioteca del controlador se carga desde el espacio de nombres default porque la persona que llama ( libRS_internal.so ) también se carga en el espacio de nombres default .

Figura 4. Ruta de respaldo de la CPU

ruta de la GPU

Para la ruta de la GPU, libRS_internal.so se carga de manera diferente. Primero, libRS.so usa android.hardware.renderscript@1.0.so (y su libhidltransport.so subyacente) para cargar android.hardware.renderscript@1.0-impl.so (una implementación de proveedor de RS HAL) en un espacio de nombres de vinculador diferente llamado sphal . Luego, RS HAL dlopen libRS_internal.so en otro espacio de nombres del vinculador llamado rs .

Los proveedores pueden proporcionar su propio controlador RS configurando el indicador de tiempo de compilación OVERRIDE_RS_DRIVER , que está integrado en la implementación RS HAL ( hardware/interfaces/renderscript/1.0/default/Context.cpp ). Luego, este nombre de controlador se dlopen para el contexto RS de la ruta de la GPU.

La creación del objeto RsContext se delega a la implementación RS HAL. HAL vuelve a llamar al marco RS utilizando la función rsContextCreateVendor() con el nombre del controlador que se utilizará como argumento. Luego, el marco RS carga el controlador especificado cuando se inicializa RsContext . En este caso, la biblioteca del controlador se carga en el espacio de nombres rs porque el objeto RsContext se crea dentro del espacio de nombres rs y /vendor/lib está en la ruta de búsqueda del espacio de nombres.

Figura 5. Ruta de respaldo de GPU

Al realizar la transición del espacio de nombres default al espacio de nombres sphal , libhidltransport.so usa la función android_load_sphal_library() para ordenar explícitamente al vinculador dinámico que cargue la biblioteca -impl.so desde el espacio de nombres sphal .

Al realizar la transición del espacio de nombres sphal al espacio de nombres rs , la carga se realiza indirectamente mediante la siguiente línea en /system/etc/ld.config.txt :

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

Esta línea especifica que el vinculador dinámico debe cargar libRS_internal.so desde el espacio de nombres rs cuando la biblioteca no se puede encontrar/cargar desde el espacio de nombres sphal (que siempre es el caso porque el espacio de nombres sphal no busca /system/lib/vndk-sp donde reside libRS_internal.so ). Con esta configuración, una simple llamada dlopen() a libRS_internal.so es suficiente para realizar la transición del espacio de nombres.

Cargando el complemento CCO

bcc plugin es una biblioteca proporcionada por el proveedor cargada en el compilador bcc . Debido a que bcc es un proceso del sistema en el directorio /system/bin , la biblioteca bcc plugin puede considerarse un SP-HAL (es decir, un HAL de proveedor que se puede cargar directamente en el proceso del sistema sin estar enlazado). Como SP-HAL, la biblioteca bcc-plugin :

  • No se puede vincular con bibliotecas exclusivas del marco, como libLLVM.so .
  • Puede vincularse únicamente con las bibliotecas VNDK-SP disponibles para el proveedor.

Esta restricción se aplica cargando el bcc plugin en el espacio de nombres sphal usando la función android_sphal_load_library() . En versiones anteriores de Android, el nombre del complemento se especificaba usando la opción -load y la biblioteca se cargaba usando el simple dlopen() de libLLVM.so . En Android 8.0 y superiores, esto se especifica en la opción -plugin y el propio bcc carga directamente la biblioteca. Esta opción habilita una ruta no específica de Android al proyecto LLVM de código abierto.

Figura 6. Cargando el complemento bcc, Android 7.x y versiones anteriores


Figura 7. Cargando el complemento bcc, Android 8.0 y superior

Rutas de búsqueda para ld.mc

Al ejecutar ld.mc , algunas bibliotecas de tiempo de ejecución de RS se proporcionan como entradas al vinculador. El código de bits RS de la aplicación está vinculado a las bibliotecas de tiempo de ejecución y cuando el código de bits convertido se carga en un proceso de aplicación, las bibliotecas de tiempo de ejecución nuevamente se vinculan dinámicamente desde el código de bits convertido.

Las bibliotecas en tiempo de ejecución incluyen:

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • Controlador RS (ya sea libRSDriver.so o OVERRIDE_RS_DRIVER )

Al cargar el código de bits compilado en el proceso de la aplicación, proporcione exactamente la misma biblioteca que utilizó ld.mc De lo contrario, es posible que el código de bits compilado no encuentre un símbolo que estuviera disponible cuando se vinculó.

Para hacerlo, RS framework utiliza diferentes rutas de búsqueda para las bibliotecas en tiempo de ejecución al ejecutar ld.mc , dependiendo de si el propio marco RS está cargado desde /system/lib o desde /system/lib/vndk-sp . Esto se puede determinar leyendo la dirección de un símbolo arbitrario de una biblioteca de marco RS y usando dladdr() para asignar la ruta del archivo a la dirección.

Política SELinux

Como resultado de los cambios en la política de SELinux en Android 8.0 y versiones posteriores, debe seguir reglas específicas (aplicadas a través de neverallows ) al etiquetar archivos adicionales en la partición vendor :

  • vendor_file debe ser la etiqueta predeterminada para todos los archivos en la partición vendor . La política de la plataforma requiere esto para acceder a implementaciones HAL de paso.
  • Todos los nuevos exec_types agregados en la partición vendor a través del proveedor SEPolicy deben tener el atributo vendor_file_type . Esto se aplica a través de neverallows .
  • Para evitar conflictos con futuras actualizaciones de plataforma/marco, evite etiquetar archivos que no sean exec_types en la partición vendor .
  • Todas las dependencias de biblioteca para HAL del mismo proceso identificados por AOSP deben etiquetarse como same_process_hal_file .

Para obtener detalles sobre la política de SELinux, consulte Linux con seguridad mejorada en Android .

Compatibilidad ABI para código de bits

Si no se agregan nuevas API, lo que significa que no habrá ningún aumento en la versión de HAL, los marcos RS seguirán usando el controlador GPU (HAL 1.0) existente.

Para cambios menores de HAL (HAL 1.1) que no afectan el código de bits, los marcos deben recurrir a la CPU para estas API recién agregadas y seguir usando el controlador GPU (HAL 1.0) en otros lugares.

Para cambios importantes de HAL (HAL 2.0) que afectan la compilación/enlace de código de bits, los marcos RS deben optar por no cargar los controladores de GPU proporcionados por el proveedor y, en su lugar, utilizar la CPU o la ruta Vulkan para la aceleración.

El consumo de código de bits de RenderScript se produce en tres etapas:

Escenario Detalles
Compilar
  • El código de bits de entrada (.bc) para bcc debe estar en formato de código de bits LLVM 3.2 y bcc debe ser compatible con aplicaciones existentes (heredadas).
  • Sin embargo, los metadatos en .bc podrían cambiar (podrían haber nuevas funciones de tiempo de ejecución, por ejemplo, definidores de asignación ∓ captadores, funciones matemáticas, etc.). Parte de las funciones de tiempo de ejecución se encuentran en libclcore.bc , parte de ellas se encuentra en LibRSDriver o equivalente del proveedor.
  • Las nuevas funciones de tiempo de ejecución o los cambios importantes en los metadatos requieren incrementar el nivel de API del código de bits. Debido a que los controladores del proveedor no podrán consumirlo, también se debe incrementar la versión HAL.
  • Los proveedores pueden tener sus propios compiladores, pero las conclusiones/requisitos de bcc también se aplican a esos compiladores.
Enlace
  • El .o compilado se vinculará con el controlador del proveedor, por ejemplo, libRSDriver_foo.so y libcompiler_rt.so . La ruta de la CPU se vinculará con libRSDriver.so .
  • Si .o requiere una nueva API de tiempo de ejecución de libRSDriver_foo , el controlador del proveedor debe actualizarse para admitirlo.
  • Ciertos proveedores pueden tener sus propios enlazadores, pero el argumento a favor de ld.mc también se aplica a ellos.
Carga
  • libRSCpuRef carga el objeto compartido. Si hay cambios en esta interfaz, se necesita un aumento de la versión HAL.
  • Los proveedores confiarían en libRSCpuRef para cargar el objeto compartido o implementarían el suyo propio.

Además de HAL, las API en tiempo de ejecución y los símbolos exportados también son interfaces. Ninguna interfaz ha cambiado desde Android 7.0 (API 24) y no hay planes inmediatos para cambiarla en Android 8.0 y versiones posteriores. Sin embargo, si la interfaz cambia, la versión HAL también aumentará.

Implementaciones de proveedores

Android 8.0 y versiones posteriores requieren algunos cambios en el controlador de GPU para que funcione correctamente.

Módulos de controlador

  • Los módulos de controlador no deben depender de ninguna biblioteca del sistema que no esté en la lista .
  • El controlador debe proporcionar su propio android.hardware.renderscript@1.0-impl_{NAME} o declarar la implementación predeterminada android.hardware.renderscript@1.0-impl como su dependencia.
  • La implementación de CPU libRSDriver.so es un buen ejemplo de cómo eliminar dependencias que no son VNDK-SP.

compilador de código de bits

Puede compilar el código de bits de RenderScript para el controlador del proveedor de dos maneras:

  1. Invoque el compilador RenderScript específico del proveedor en /vendor/bin/ (método preferido de compilación de GPU). Al igual que otros módulos de controlador, el binario del compilador del proveedor no puede depender de ninguna biblioteca del sistema que no esté en la lista de bibliotecas de RenderScript disponibles para los proveedores .
  2. Invocar sistema bcc: /system/bin/bcc con un bcc plugin proporcionado por el proveedor; Este complemento no puede depender de ninguna biblioteca del sistema que no esté en la lista de bibliotecas de RenderScript disponibles para los proveedores .

Si el bcc plugin del proveedor necesita interferir con la compilación de la CPU y su dependencia de libLLVM.so no se puede eliminar fácilmente, el proveedor debe copiar bcc (y todas las dependencias que no sean LL-NDK, incluidas libLLVM.so y libbcc.so ) en /vendor .

Además, los proveedores deben realizar los siguientes cambios:

Figura 8. Cambios en el controlador del proveedor
  1. Copie libclcore.bc a la partición /vendor . Esto garantiza libclcore.bc , libLLVM.so y libbcc.so estén sincronizados.
  2. Cambie la ruta al ejecutable bcc configurando RsdCpuScriptImpl::BCC_EXE_PATH desde la implementación RS HAL.

Política SELinux

La política de SELinux afecta tanto al controlador como a los ejecutables del compilador. Todos los módulos de controlador deben estar etiquetados same_process_hal_file en los file_contexts del dispositivo. Por ejemplo:

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

El ejecutable del compilador debe poder ser invocado por un proceso de aplicación, al igual que la copia del proveedor de bcc ( /vendor/bin/bcc ). Por ejemplo:

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

Dispositivos heredados

Los dispositivos heredados son aquellos que cumplen las siguientes condiciones:

  1. PRODUCT_SHIPPING_API_LEVEL es inferior a 26.
  2. PRODUCT_FULL_TREBLE_OVERRIDE no está definido.

Para los dispositivos heredados, las restricciones no se aplican al actualizar a Android 8.0 y superior, lo que significa que los controladores pueden continuar vinculándose a las bibliotecas en /system/lib[64] . Sin embargo, debido al cambio de arquitectura relacionado con OVERRIDE_RS_DRIVER , android.hardware.renderscript@1.0-impl debe instalarse en la partición /vendor ; De no hacerlo, el tiempo de ejecución de RenderScript se verá obligado a recurrir a la ruta de la CPU.

Para obtener información sobre los motivos de la desactivación de Renderscript, consulte el blog de desarrolladores de Android: Computación de GPU de Android en el futuro . La información de recursos para esta desaprobación incluye lo siguiente: