RenderScript

RenderScript est un framework qui permet d'exécuter des tâches nécessitant beaucoup de ressources de calcul sur Android. Il est conçu pour être utilisé avec le calcul parallèle des données, même si les charges de travail en série peuvent également en bénéficier. L'environnement d'exécution RenderScript exécute les tâches en parallèle sur les processeurs disponibles sur l'appareil tels que les GPU et les processeurs multicœurs, ce qui permet aux développeurs de se concentrer sur l'expression d'algorithmes plutôt que sur la planification des tâches. RenderScript est particulièrement utile pour les applications de traitement d'images, de photographie computationnelle ou de vision par ordinateur.

Les appareils équipés d'Android 8.0 ou version ultérieure utilisent les HAL du fournisseur et le framework RenderScript suivants :

Figure 1 : Liaison du code du fournisseur à des bibliothèques internes.

Voici les différences avec RenderScript dans Android 7.x et versions antérieures :

  • Deux instances de bibliothèques internes RenderScript dans un processus. Un ensemble est destiné au chemin de secours du processeur et provient directement de /system/lib. L'autre ensemble est destiné au chemin du GPU et provient de /system/lib/vndk-sp.
  • Les bibliothèques internes RS dans /system/lib sont créées dans le cadre de la plate-forme et sont mises à jour lorsque system.img est mis à niveau. Toutefois, les libs de /system/lib/vndk-sp sont conçues pour le fournisseur et ne sont pas mises à jour lorsque system.img est mis à niveau (bien qu'elles puissent être mises à jour pour corriger un problème de sécurité, leur ABI reste la même).
  • Le code du fournisseur (RS HAL, pilote RS et bcc plugin) est lié aux bibliothèques internes RenderScript situées à l'adresse /system/lib/vndk-sp. Ils ne peuvent pas établir de lien avec les bibliothèques dans /system/lib, car les bibliothèques de ce répertoire sont conçues pour la plate-forme et peuvent donc ne pas être compatibles avec le code du fournisseur (c'est-à-dire que des symboles peuvent être supprimés). Cela rendrait impossible une mise à jour OTA du framework uniquement.

Conception

Les sections suivantes décrivent la conception de RenderScript dans Android 8.0 et versions ultérieures.

Bibliothèques RenderScript disponibles pour les fournisseurs

Cette section liste les bibliothèques RenderScript (appelées Vendor NDK pour les HAL Same-Process ou VNDK-SP) qui sont disponibles pour le code du fournisseur et qui peuvent être liées. Il détaille également les bibliothèques supplémentaires qui ne sont pas liées à RenderScript, mais qui sont également fournies au code du fournisseur.

Bien que la liste de bibliothèques suivante puisse varier d'une version d'Android à l'autre, elle est immuable pour une version d'Android spécifique. Pour obtenir une liste à jour des bibliothèques disponibles, consultez /system/etc/ld.config.txt.

Bibliothèques RenderScript Bibliothèques non 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

Configuration de l'espace de noms du linker

La restriction d'association qui empêche le code du fournisseur d'utiliser des bibliothèques qui ne se trouvent pas dans VNDK-SP est appliquée au moment de l'exécution à l'aide de l'espace de noms de l'éditeur de liens. (Pour en savoir plus, consultez la présentation VNDK Design.)

Sur un appareil équipé d'Android 8.0 ou version ultérieure, toutes les HAL (Hardware Abstraction Layer) du même processus (SP-HAL) sauf RenderScript sont chargées dans l'espace de noms de l'éditeur de liens sphal. RenderScript est chargé dans l'espace de noms rs spécifique à RenderScript, un emplacement qui permet une application légèrement moins stricte pour les bibliothèques RenderScript. Étant donné que l'implémentation RS doit charger le bitcode compilé, /data/*/*.so est ajouté au chemin d'accès de l'espace de noms rs (les autres SP-HAL ne sont pas autorisés à charger des bibliothèques à partir de la partition de données).

De plus, l'espace de noms rs autorise plus de bibliothèques que les autres espaces de noms. libmediandk.so et libft2.so sont exposés à l'espace de noms rs, car libRS_internal.so a une dépendance interne à ces bibliothèques.

Figure 2. Configuration de l'espace de noms pour l'outil d'association.

Charger les pilotes

Chemin de remplacement du processeur

Selon l'existence du bit RS_CONTEXT_LOW_LATENCY lors de la création d'un contexte RS, le chemin d'accès au processeur ou au GPU est sélectionné. Lorsque le chemin d'accès au processeur est sélectionné, libRS_internal.so (l'implémentation principale du framework RS) est directement dlopen à partir de l'espace de noms de l'éditeur de liens par défaut où la version de plate-forme des bibliothèques RS est fournie.

L'implémentation RS HAL du fournisseur n'est pas du tout utilisée lorsque le chemin de secours du processeur est emprunté, et un objet RsContext est créé avec mVendorDriverName nul. libRSDriver.so est (par défaut) dlopen et la bibliothèque de pilotes est chargée à partir de l'espace de noms default, car l'appelant (libRS_internal.so) est également chargé dans l'espace de noms default.

Figure 3. Chemin de remplacement du processeur.

Chemin d'accès au GPU

Pour le chemin d'accès au GPU, libRS_internal.so est chargé différemment. Tout d'abord, libRS.so utilise android.hardware.renderscript@1.0.so (et son libhidltransport.so sous-jacent) pour charger android.hardware.renderscript@1.0-impl.so (une implémentation fournisseur de RS HAL) dans un autre espace de noms de l'éditeur de liens appelé sphal. La HAL RS dlopen ensuite libRS_internal.so dans un autre espace de noms de l'éditeur de liens appelé rs.

Les fournisseurs peuvent fournir leur propre pilote RS en définissant l'indicateur de compilation OVERRIDE_RS_DRIVER, qui est intégré à l'implémentation RS HAL (hardware/interfaces/renderscript/1.0/default/Context.cpp). Ce nom de pilote est ensuite dlopen pour le contexte RS pour le chemin d'accès au GPU.

La création de l'objet RsContext est déléguée à l'implémentation RS HAL. Le HAL rappelle le framework RS à l'aide de la fonction rsContextCreateVendor() avec le nom du pilote à utiliser comme argument. Le framework RS charge ensuite le pilote spécifié lors de l'initialisation de RsContext. Dans ce cas, la bibliothèque de pilotes est chargée dans l'espace de noms rs, car l'objet RsContext est créé dans l'espace de noms rs et /vendor/lib se trouve dans le chemin de recherche de l'espace de noms.

Figure 4. Chemin de secours du GPU.

Lors du passage de l'espace de noms default à l'espace de noms sphal, libhidltransport.so utilise la fonction android_load_sphal_library() pour ordonner explicitement au linker dynamique de charger la bibliothèque -impl.so à partir de l'espace de noms sphal.

Lors du passage de l'espace de noms sphal à l'espace de noms rs, le chargement est effectué indirectement par la ligne suivante dans /system/etc/ld.config.txt :

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

Cette ligne indique que l'éditeur de liens dynamiques doit charger libRS_internal.so à partir de l'espace de noms rs lorsque la bibliothèque ne peut pas être trouvée ni chargée à partir de l'espace de noms sphal (ce qui est toujours le cas, car l'espace de noms sphal ne recherche pas /system/lib/vndk-sp où se trouve libRS_internal.so). Avec cette configuration, un simple appel dlopen() à libRS_internal.so suffit pour effectuer la transition de l'espace de noms.

Charger le plug-in Cci

bcc plugin est une bibliothèque fournie par le fournisseur et chargée dans le compilateur bcc. Étant donné que bcc est un processus système dans le répertoire /system/bin, la bibliothèque bcc plugin peut être considérée comme une SP-HAL (c'est-à-dire une HAL du fournisseur qui peut être directement chargée dans le processus système sans être binderisée). En tant que SP-HAL, la bibliothèque bcc-plugin :

  • Vous ne pouvez pas créer de lien vers des bibliothèques de framework uniquement, telles que libLLVM.so.
  • Il ne peut être associé qu'aux bibliothèques VNDK-SP disponibles pour le fournisseur.

Cette restriction est appliquée en chargeant bcc plugin dans l'espace de noms sphal à l'aide de la fonction android_sphal_load_library(). Dans les versions précédentes d'Android, le nom du plug-in était spécifié à l'aide de l'option -load et la bibliothèque était chargée à l'aide du simple dlopen() par libLLVM.so. Dans Android 8.0 ou version ultérieure, cette option est spécifiée dans l'option -plugin et la bibliothèque est directement chargée par bcc lui-même. Cette option permet d'accéder à un chemin d'accès non spécifique à Android vers le projet LLVM Open Source.

Figure 5. Chargement du plug-in bcc, Android 7.x et versions antérieures.



Figure 6. Chargement du plug-in bcc, Android 8.0 et versions ultérieures.

Chemins de recherche pour ld.mc

Lors de l'exécution de ld.mc, certaines bibliothèques d'exécution RS sont fournies en tant qu'entrées au linker. Le bitcode RS de l'application est lié aux bibliothèques d'exécution. Lorsque le bitcode converti est chargé dans un processus d'application, les bibliothèques d'exécution sont à nouveau liées dynamiquement à partir du bitcode converti.

Les bibliothèques d'exécution incluent :

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • Pilote RS (libRSDriver.so ou OVERRIDE_RS_DRIVER)

Lorsque vous chargez le bitcode compilé dans le processus de l'application, fournissez exactement la même bibliothèque que celle utilisée par ld.mc. Sinon, le bitcode compilé risque de ne pas trouver un symbole qui était disponible lors de sa liaison.

Pour ce faire, le framework RS utilise différents chemins de recherche pour les bibliothèques d'exécution lors de l'exécution de ld.mc, selon que le framework RS lui-même est chargé à partir de /system/lib ou de /system/lib/vndk-sp. Pour ce faire, lisez l'adresse d'un symbole arbitraire d'une bibliothèque de framework RS et utilisez dladdr() pour obtenir le chemin d'accès au fichier mappé à l'adresse.

Règle SELinux

En raison des modifications apportées aux règles SELinux dans Android 8.0 et versions ultérieures, vous devez suivre des règles spécifiques (appliquées via neverallows) lorsque vous ajoutez des libellés à des fichiers dans la partition vendor :

  • vendor_file doit être le libellé par défaut pour tous les fichiers de la partition vendor. La règle de la plate-forme exige cela pour accéder aux implémentations HAL pass-through.
  • Tous les nouveaux exec_types ajoutés dans la partition vendor via la SEPolicy du fournisseur doivent avoir l'attribut vendor_file_type. Cela est appliqué par le biais de neverallows.
  • Pour éviter les conflits avec les futures mises à jour de la plate-forme/du framework, évitez de libeller les fichiers autres que exec_types dans la partition vendor.
  • Toutes les dépendances de bibliothèque pour les HAL de même processus identifiés par l'AOSP doivent être étiquetées same_process_hal_file.

Pour en savoir plus sur la stratégie SELinux, consultez Security-Enhanced Linux dans Android.

Compatibilité ABI pour le bitcode

Si aucune nouvelle API n'est ajoutée, ce qui signifie qu'aucune version HAL n'est mise à jour, les frameworks RS continueront d'utiliser le pilote GPU existant (HAL 1.0).

Pour les modifications mineures de HAL (HAL 1.1) n'affectant pas le bitcode, les frameworks doivent revenir au processeur pour ces API nouvellement ajoutées et continuer à utiliser le pilote GPU (HAL 1.0) ailleurs.

Pour les modifications majeures de HAL (HAL 2.0) affectant la compilation/l'association de bitcode, les frameworks RS ne doivent pas charger les pilotes GPU fournis par le fournisseur et doivent plutôt utiliser le chemin d'accès CPU ou Vulkan pour l'accélération.

La consommation de bitcode RenderScript se déroule en trois étapes :

Scène Détails
Compiler
  • Le bitcode d'entrée (.bc) pour bcc doit être au format bitcode LLVM 3.2 et bcc doit être rétrocompatible avec les applications existantes (anciennes).
  • Toutefois, les métadonnées du fichier .bc peuvent changer (de nouvelles fonctions d'exécution peuvent être ajoutées, par exemple). (fonctions setter et getter d'allocation, fonctions mathématiques, etc.). Une partie des fonctions d'exécution se trouve dans libclcore.bc, une autre dans LibRSDriver ou l'équivalent du fournisseur.
  • Les nouvelles fonctions d'exécution ou les modifications destructives des métadonnées nécessitent d'incrémenter le niveau d'API du bitcode. Étant donné que les pilotes du fournisseur ne pourront pas l'utiliser, la version HAL doit également être incrémentée.
  • Les fournisseurs peuvent avoir leurs propres compilateurs, mais les conclusions/exigences pour bcc s'appliquent également à ces compilateurs.
Lien
  • Le fichier .o compilé sera associé au pilote du fournisseur, par exemple : libRSDriver_foo.so et libcompiler_rt.so. Le chemin d'accès au CPU sera associé à libRSDriver.so.
  • Si le fichier .o nécessite une nouvelle API d'exécution à partir de libRSDriver_foo, le pilote du fournisseur doit être mis à jour pour la prendre en charge.
  • Certains fournisseurs peuvent avoir leurs propres linkers, mais l'argument pour ld.mc s'applique également à eux.
Charger
  • libRSCpuRef charge l'objet partagé. Si des modifications sont apportées à cette interface, une mise à jour de la version HAL est nécessaire.
  • Les fournisseurs s'appuient sur libRSCpuRef pour charger l'objet partagé ou implémentent le leur.

En plus de la HAL, les API d'exécution et les symboles exportés sont également des interfaces. Aucune des deux interfaces n'a changé depuis Android 7.0 (API 24) et il n'est pas prévu de les modifier dans Android 8.0 et les versions ultérieures. Toutefois, si l'interface change, la version HAL sera également incrémentée.

Implémentations par les fournisseurs

Android 8.0 et versions ultérieures nécessitent certaines modifications du pilote GPU pour que celui-ci fonctionne correctement.

Modules de pilote

  • Les modules de pilotes ne doivent dépendre d'aucune bibliothèque système qui ne figure pas dans la liste.
  • Le pilote doit fournir son propre android.hardware.renderscript@1.0-impl_{NAME} ou déclarer l'implémentation par défaut android.hardware.renderscript@1.0-impl comme dépendance.
  • L'implémentation du processeur libRSDriver.so est un bon exemple de la façon de supprimer les dépendances non-VNDK-SP.

Compilateur Bitcode

Vous pouvez compiler le bitcode RenderScript pour le pilote du fournisseur de deux manières :

  1. Invoquez le compilateur RenderScript spécifique au fournisseur dans /vendor/bin/ (méthode de compilation GPU recommandée). Comme les autres modules de pilote, le binaire du compilateur du fournisseur ne peut dépendre d'aucune bibliothèque système qui ne figure pas dans la liste des bibliothèques RenderScript disponibles pour les fournisseurs.
  2. Appelez le système Ccn : /system/bin/bcc avec un bcc plugin fourni par le fournisseur. Ce plug-in ne peut dépendre d'aucune bibliothèque système qui ne figure pas dans la liste des bibliothèques RenderScript disponibles pour les fournisseurs.

Si le fournisseur bcc plugin doit interférer avec la compilation du processeur et que sa dépendance à libLLVM.so ne peut pas être facilement supprimée, il doit copier bcc (et toutes les dépendances non-LL-NDK, y compris libLLVM.so et libbcc.so) dans la partition /vendor.

De plus, les fournisseurs doivent apporter les modifications suivantes :

Figure 7. Modifications apportées au pilote du fournisseur.

  1. Copiez libclcore.bc dans la partition /vendor. Cela permet de s'assurer que libclcore.bc, libLLVM.so et libbcc.so sont synchronisés.
  2. Modifiez le chemin d'accès à l'exécutable bcc en définissant RsdCpuScriptImpl::BCC_EXE_PATH à partir de l'implémentation RS HAL.

Règle SELinux

La règle SELinux affecte à la fois les exécutables du pilote et du compilateur. Tous les modules de pilote doivent être étiquetés same_process_hal_file dans le file_contexts de l'appareil. Exemple :

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

L'exécutable du compilateur doit pouvoir être appelé par un processus d'application, tout comme la copie du fournisseur de bcc (/vendor/bin/bcc). Par exemple :

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

Anciens appareils

Les anciens appareils sont ceux qui remplissent les conditions suivantes :

  1. PRODUCT_SHIPPING_API_LEVEL est inférieur à 26.
  2. PRODUCT_FULL_TREBLE_OVERRIDE n'est pas défini.

Pour les anciens appareils, les restrictions ne sont pas appliquées lors de la mise à niveau vers Android 8.0 ou version ultérieure. Cela signifie que les pilotes peuvent continuer à établir un lien vers les bibliothèques dans /system/lib[64]. Toutefois, en raison du changement d'architecture lié à OVERRIDE_RS_DRIVER, android.hardware.renderscript@1.0-impl doit être installé dans la partition /vendor. Si ce n'est pas le cas, l'environnement d'exécution RenderScript est forcé de revenir au chemin d'accès du processeur.

Pour en savoir plus sur les raisons de l'abandon de Renderscript, consultez le blog Android Developers : Android GPU Compute Going Forward. Les informations sur les ressources pour cet abandon incluent les éléments suivants :