Renderscript

RenderScript es un marco para ejecutar tareas computacionalmente intensivas con alto rendimiento en Android. Está diseñado para usarse con computación paralela de datos, 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 multinúcleo, lo que permite a los desarrolladores concentrarse 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 artificial.

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

Figura 1. Enlace de código de proveedor 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 de respaldo de la CPU y proviene directamente de /system/lib ; el otro conjunto es para la ruta de GPU y es de /system/lib/vndk-sp .
  • Las bibliotecas internas de RS en /system/lib se construyen como parte de la plataforma y se actualizan a medida que se actualiza system.img . Sin embargo, las librerías en /system/lib/vndk-sp están diseñadas para el proveedor y no se actualizan cuando se actualiza system.img (aunque se pueden actualizar para una solución de seguridad, su ABI sigue siendo la misma).
  • El código del proveedor (RS HAL, el controlador RS y el bcc plugin ) están vinculados a las bibliotecas internas de RenderScript ubicadas en /system/lib/vndk-sp . No se pueden vincular con bibliotecas en /system/lib porque las bibliotecas en ese directorio están diseñadas para la plataforma y, por lo tanto, es posible que no sean compatibles con el código del proveedor (es decir, se pueden eliminar los símbolos). Hacerlo haría imposible una OTA solo de marco.

Diseño

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

Librerías 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 del 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 al 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 Librerías sin 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 enlazador

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

En un dispositivo que ejecuta Android 8.0 y versiones posteriores, todas las 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 un poco menos estricta de 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 con estas bibliotecas.

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

Cargando controladores

Ruta de respaldo de la CPU

Según la existencia del bit RS_CONTEXT_LOW_LATENCY al crear un contexto RS, se selecciona la ruta de la CPU o la 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 enlazador predeterminado donde se proporciona la versión de plataforma de RS libs.

La implementación de RS HAL del proveedor no se usa en absoluto cuando se toma la ruta de respaldo de la CPU y se crea un objeto RsContext con mVendorDriverName nulo. libRSDriver.so está (de manera predeterminada) dlopen 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 GPU

Para la ruta de 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 enlazador diferente llamado sphal El RS HAL entonces dlopen s libRS_internal.so en otro espacio de nombres del enlazador 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 para la ruta de la GPU.

La creación del objeto RsContext se delega a la implementación de RS HAL. El HAL vuelve a llamar al marco de trabajo de RS utilizando la función rsContextCreateVendor() con el nombre del controlador para usar como argumento. El marco RS luego carga el controlador especificado cuando se inicializa RsContext . En este caso, la biblioteca de controladores 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 pasar 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 pasar 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 no se puede encontrar/cargar lib desde el espacio de nombres sphal (que siempre es el caso porque el espacio de nombres sphal no busca /system/lib/vndk-sp donde libRS_internal.so reside). 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 BCC

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

  • No se puede vincular con bibliotecas solo de marco como libLLVM.so .
  • Puede vincularse solo con las bibliotecas VNDK-SP disponibles para el proveedor.

Esta restricción se aplica cargando el bcc plugin bcc en el espacio de nombres sphal mediante la función android_sphal_load_library() . En versiones anteriores de Android, el nombre del complemento se especificaba con la opción -load y la lib se cargaba con el simple dlopen() de libLLVM.so . En Android 8.0 y versiones posteriores, esto se especifica en la opción -plugin y la lib la carga directamente el propio bcc . 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 anterior


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 para el enlazador. El código de bits RS de la aplicación se vincula con las bibliotecas de tiempo de ejecución y cuando el código de bits convertido se carga en un proceso de la aplicación, las bibliotecas de tiempo de ejecución se vinculan de nuevo dinámicamente desde el código de bits convertido.

Las bibliotecas de 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 estaba disponible cuando se vinculó.

Para hacerlo, el marco RS usa diferentes rutas de búsqueda para las librerías en tiempo de ejecución al ejecutar ld.mc , dependiendo de si el marco RS se carga desde /system/lib o desde /system/lib/vndk-sp . Esto se puede determinar leyendo la dirección de un símbolo arbitrario de una lib de marco RS y usando dladdr() para obtener la ruta del archivo asignada a la dirección.

Política de 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 neverallows ) al etiquetar archivos adicionales en la partición del vendor :

  • vendor_file debe ser la etiqueta predeterminada para todos los archivos en la partición del vendor . La política de la plataforma requiere esto para acceder a las implementaciones HAL de acceso directo.
  • Todos los nuevos exec_types agregados en la partición del vendor a través del proveedor vendor_file_type deben tener el atributo de proveedor_archivo_tipo. Esto se aplica mediante neverallows .
  • Para evitar conflictos con futuras actualizaciones de plataforma/marco, evite etiquetar archivos que no sean exec_types en la partición del vendor .
  • Todas las dependencias de la biblioteca para las HAL del mismo proceso identificadas 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 hay un aumento de la versión HAL, los marcos RS seguirán usando el controlador de GPU (HAL 1.0) existente.

Para los 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 los cambios importantes de HAL (HAL 2.0) que afectan la compilación/vinculación de códigos de bits, los marcos RS deben elegir no cargar los controladores de GPU proporcionados por el proveedor y, en su lugar, usar la ruta de CPU o 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 anteriores (heredadas).
  • Sin embargo, los metadatos en .bc podrían cambiar (podría haber nuevas funciones de tiempo de ejecución, por ejemplo, establecedores de asignación ∓ captadores, funciones matemáticas, etc.). Parte de las funciones de tiempo de ejecución viven en libclcore.bc , parte de ellas vive en LibRSDriver o el equivalente del proveedor.
  • Las nuevas funciones de tiempo de ejecución o los cambios importantes en los metadatos requieren incrementar el nivel de la API de código de bits. Debido a que los controladores del proveedor no podrán consumirlo, la versión HAL también debe incrementarse.
  • Los proveedores pueden tener sus propios compiladores, pero las conclusiones/requisitos para 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 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 de 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 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 el controlador de GPU funcione correctamente.

Módulos de controlador

  • Los módulos de controladores 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 las dependencias que no son de 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 de RenderScript específico del proveedor en /vendor/bin/ (método preferido de compilación de GPU). Al igual que otros módulos de controladores, 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. Invoque system 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 , libbcc.so ) en partición /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 de RS HAL.

Política de SELinux

La política de SELinux afecta tanto al controlador como a los ejecutables del compilador. Todos los módulos del controlador deben tener la etiqueta same_process_hal_file en los contextos de 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 cuando se actualiza a Android 8.0 y versiones posteriores, lo que significa que los controladores pueden seguir 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 ; si no lo hace, obliga al tiempo de ejecución de RenderScript a volver a la ruta de la CPU.

Para obtener información sobre los motivos de la desaprobación de Renderscript, consulte el blog de desarrolladores de Android: Android GPU Compute Going Forward . La información de recursos para esta degradación incluye lo siguiente: