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 le framework RenderScript et les HAL du fournisseur suivants:

Figure 1 : Code fournisseur redirigeant vers les bibliothèques internes.

Les différences par rapport à RenderScript sur Android 7.x et versions antérieures incluent les suivantes:

  • Deux instances de bibliothèques internes RenderScript dans un processus. L'un est destiné au chemin d'accès de remplacement du processeur et provient directement de /system/lib. L'autre est destiné au chemin d'accès 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 à mesure que system.img est mis à niveau. Toutefois, les bibliothèques de /system/lib/vndk-sp sont compilées pour le fournisseur et ne sont pas mises à jour lors de la mise à niveau de system.img (bien qu'elles puissent être mises à jour pour un correctif de sécurité, leur ABI reste la même).
  • Le code du fournisseur (HAL RS, pilote RS et bcc plugin) est associé aux bibliothèques internes de RenderScript situées dans /system/lib/vndk-sp. Ils ne peuvent pas lier les libs dans /system/lib, car les libs de ce répertoire sont compilées 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 uniquement pour le framework.

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 (connues sous le nom de NDK fournisseur pour les HAL Same-Process ou VNDK-SP) disponibles pour le code fournisseur et avec lesquelles elles peuvent être associées. Il détaille également les bibliothèques supplémentaires qui n'ont aucun lien avec 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 spécifique d'Android. Pour obtenir une liste à jour des bibliothèques disponibles, reportez-vous à /system/etc/ld.config.txt.

Bibliothèques RenderScript Bibliothèques autres que 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 l'utilisation des bibliothèques qui ne figurent pas dans VNDK-SP par le code du fournisseur est appliquée au moment de l'exécution à l'aide de l'espace de noms du linker. (Pour en savoir plus, consultez la présentation de la conception du VNDK.)

Sur un appareil équipé d'Android 8.0 ou version ultérieure, tous les HAL du même processus (SP-HAL) sauf RenderScript sont chargés dans l'espace de noms du linker sphal. RenderScript est chargé dans l'espace de noms rs spécifique à RenderScript, un emplacement qui permet une application légèrement plus souple des règles pour les bibliothèques RenderScript. Étant donné que la mise en œuvre 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 celles fournies par d'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 le linker.

Charger les pilotes

Chemin de remplacement du CPU

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 dlopen directement à partir du namespace du linker 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 utilisée du tout lorsque le chemin de remplacement du processeur est emprunté et qu'un objet RsContext est créé avec une valeur mVendorDriverName nulle. libRSDriver.so est (par défaut) dlopened et la bibliothèque du pilote 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 du HAL RS par le fournisseur) dans un autre espace de noms de l'éditeur de liens appelé sphal. Le 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 temps de compilation OVERRIDE_RS_DRIVER, qui est intégré à l'implémentation du HAL RS (hardware/interfaces/renderscript/1.0/default/Context.cpp). Ce nom de pilote est ensuite dlopené pour le contexte RS du chemin d'accès au GPU.

La création de l'objet RsContext est déléguée à l'implémentation du HAL RS. Le HAL appelle 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é lorsque RsContext est initialisé. 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 d'accès de remplacement du GPU.

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

Lors de la transition de l'espace de noms sphal vers 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 dynamique doit charger libRS_internal.so à partir de l'espace de noms rs lorsque la bibliothèque ne peut pas être trouvée/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-splibRS_internal.so se trouve). Avec cette configuration, un simple appel dlopen() à libRS_internal.so suffit à effectuer la transition d'espace de noms.

Charger le plug-in de Cci

bcc plugin est une bibliothèque fournie par le fournisseur 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 un SP-HAL (c'est-à-dire un HAL du fournisseur pouvant être chargé directement dans le processus système sans être lié). En tant que SP-HAL, la bibliothèque bcc-plugin:

  • Impossible d'établir un lien avec des bibliothèques basées uniquement sur le framework, telles que libLLVM.so.
  • Ne peut lier que les 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 de dlopen() simple par libLLVM.so. Dans Android 8.0 et versions ultérieures, cela est spécifié dans l'option -plugin, et la bibliothèque est directement chargée par bcc lui-même. Cette option active un chemin 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 ou version ultérieure.

Chemins de recherche pour ld.mc

Lors de l'exécution de ld.mc, certaines bibliothèques d'exécution RS sont fournies en entrée au l'éditeur de liens. Le bitcode RS de l'application est lié aux bibliothèques d'exécution et, 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 les éléments suivants:

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

Lors du chargement du 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 de symbole disponible lors de l'association.

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é sur 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 attribuez des libellés à des fichiers supplémentaires 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 nécessite cela pour accéder aux implémentations HAL de passthrough.
  • Tous les nouveaux exec_types ajoutés dans la partition vendor via le SEPolicy du fournisseur doivent avoir l'attribut vendor_file_type. Cette règle est appliquée via neverallows.
  • Pour éviter les conflits avec les futures mises à jour de la plate-forme/du framework, évitez d'étiqueter des fichiers autres que exec_types dans la partition vendor.
  • Toutes les dépendances de bibliothèque pour les HAL du même processus identifiées par l'AOSP doivent être libellées same_process_hal_file.

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

Compatibilité avec les ABI pour le bitcode

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

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

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

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

Étape Détails
Compilation
  • Le code binaire d'entrée (.bc) pour bcc doit être au format de code binaire LLVM 3.2, et bcc doit être rétrocompatible avec les applications existantes (anciennes).
  • Toutefois, les métadonnées du fichier .bc peuvent changer (il peut y avoir de nouvelles fonctions d'exécution, par exemple, (setters et getters d'allocation, fonctions mathématiques, etc.). Une partie des fonctions d'exécution se trouve dans libclcore.bc, et une autre dans LibRSDriver ou un équivalent fournisseur.
  • Les nouvelles fonctions d'exécution ou les modifications de métadonnées destructives nécessitent d'augmenter le niveau d'API du code binaire. Étant donné que les pilotes de fournisseur ne pourront pas l'utiliser, la version de 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 processeur sera associé à libRSDriver.so.
  • Si le fichier .o nécessite une nouvelle API d'exécution de libRSDriver_foo, le pilote du fournisseur doit être mis à jour pour le 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 cette interface est modifiée, une mise à niveau 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 du HAL, les API d'exécution et les symboles exportés sont également des interfaces. Aucune de ces deux interfaces n'a changé depuis Android 7.0 (API 24), et il n'est pas prévu de la modifier dans l'immédiat sous Android 8.0 et versions ultérieures. Toutefois, si l'interface change, la version de HAL est également incrémentée.

Implémentations des fournisseurs

Android 8.0 ou version ultérieure nécessite certaines modifications du pilote de GPU pour que celui-ci fonctionne correctement.

Modules pilotes

  • Les modules pilotes ne doivent pas dépendre de bibliothèques système qui ne figurent pas dans cette 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 de code binaire

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

  1. Appelez le compilateur RenderScript spécifique au fournisseur dans /vendor/bin/ (méthode de compilation du GPU recommandée). Comme les autres modules de pilotes, le binaire du compilateur du fournisseur ne peut pas dépendre d'une bibliothèque système qui ne figure pas dans la liste des bibliothèques RenderScript disponibles pour les fournisseurs.
  2. Appelez le bcc système: /system/bin/bcc avec un bcc plugin fourni par le fournisseur. Ce plug-in ne peut pas dépendre d'une 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 envers libLLVM.so ne peut pas être facilement supprimée, le fournisseur doit copier bcc (et toutes les dépendances autres que LL-NDK, y compris libLLVM.so, libbcc.so) dans la partition /vendor.

Les fournisseurs doivent également apporter les modifications suivantes:

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

  1. Copiez libclcore.bc dans la partition /vendor. Cela garantit 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 s'applique à la fois au pilote et aux exécutables 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, comme le fait 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

Appareils anciens

Les anciens appareils sont ceux qui remplissent les conditions suivantes:

  1. La valeur de PRODUCT_SHIPPING_API_LEVEL est inférieure à 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, ce qui signifie que les pilotes peuvent continuer à associer des 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 vous ne le faites pas, l'environnement d'exécution RenderScript est forcé de revenir au chemin d'accès du processeur.

Pour en savoir plus sur la raison de l'abandon de Renderscript, consultez le blog des développeurs Android: Android GPU Compute Going Forward (Calcul GPU Android à l'avenir). Les informations sur les ressources pour cette abandon incluent les éléments suivants: