RenderScript

RenderScript ist ein Framework zum Ausführen rechenintensiver Aufgaben mit hoher Leistung auf Android. Sie ist für die datenparallele Berechnung konzipiert, kann aber auch für serielle Arbeitslasten verwendet werden. Die RenderScript-Laufzeit parallelisiert die Arbeit auf den auf einem Gerät verfügbaren Prozessoren, z. B. Mehrkern-CPUs und GPUs. So können sich Entwickler auf die Formulierung von Algorithmen konzentrieren, anstatt die Arbeit zu planen. RenderScript ist besonders nützlich für Apps, die Bildverarbeitung, Computational Photography oder Computer Vision nutzen.

Auf Geräten mit Android 8.0 und höher werden die folgenden RenderScript-Frameworks und Vendor-HALs verwendet:

Abbildung 1: Anbietercode, der auf interne Bibliotheken verweist.

Unterschiede zu RenderScript in Android 7.x und niedriger:

  • Zwei Instanzen von internen RenderScript-Bibliotheken in einem Prozess. Ein Satz ist für den CPU-Fallback-Pfad und stammt direkt von /system/lib. Der andere Satz ist für den GPU-Pfad und stammt von /system/lib/vndk-sp.
  • Interne RS-Bibliotheken in /system/lib werden als Teil der Plattform erstellt und bei einem Upgrade von system.img aktualisiert. Die Bibliotheken in /system/lib/vndk-sp werden jedoch für den Anbieter erstellt und nicht aktualisiert, wenn system.img aktualisiert wird. Sie können zwar für einen Sicherheitsfix aktualisiert werden, ihr ABI bleibt jedoch gleich.
  • Der Anbietercode (RS HAL, RS-Treiber und bcc plugin) wird mit den internen RenderScript-Bibliotheken unter /system/lib/vndk-sp verknüpft. Sie können keine Verknüpfung zu Bibliotheken in /system/lib herstellen, da Bibliotheken in diesem Verzeichnis für die Plattform erstellt werden und daher möglicherweise nicht mit dem Anbietercode kompatibel sind (d.h., Symbole können entfernt werden). Andernfalls wäre ein OTA nur für das Framework nicht möglich.

Design

In den folgenden Abschnitten wird das RenderScript-Design in Android 8.0 und höher beschrieben.

Für Anbieter verfügbare RenderScript-Bibliotheken

In diesem Abschnitt werden die RenderScript-Bibliotheken (als Vendor NDK für Same-Process-HALs oder VNDK-SP bezeichnet) aufgeführt, die für Anbietercode verfügbar sind und mit denen verknüpft werden kann. Außerdem werden zusätzliche Bibliotheken beschrieben, die nicht mit RenderScript zusammenhängen, aber auch für den Anbietercode bereitgestellt werden.

Die folgende Liste von Bibliotheken kann sich zwischen Android-Releases unterscheiden, ist aber für ein bestimmtes Android-Release unveränderlich. Eine aktuelle Liste der verfügbaren Bibliotheken finden Sie unter /system/etc/ld.config.txt.

RenderScript-Bibliotheken Nicht-RenderScript-Bibliotheken
  • 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

Linker-Namespace-Konfiguration

Die Verknüpfungsbeschränkung, die verhindert, dass Bibliotheken, die nicht in VNDK-SP enthalten sind, von Anbietercode verwendet werden, wird zur Laufzeit mithilfe des Linker-Namespace erzwungen. Weitere Informationen finden Sie in der Präsentation VNDK Design.

Auf Geräten mit Android 8.0 und höher werden alle Same-Process-HALs (SP-HALs) mit Ausnahme von RenderScript im Linker-Namespace sphal geladen. RenderScript wird in den RenderScript-spezifischen Namespace rs geladen. An diesem Speicherort gelten etwas weniger strenge Regeln für RenderScript-Bibliotheken. Da die RS-Implementierung den kompilierten Bitcode laden muss, wird /data/*/*.so dem Pfad des rs-Namespace hinzugefügt. Andere SP-HALs dürfen keine Bibliotheken aus der Datenpartition laden.

Außerdem sind im rs-Namespace mehr Bibliotheken zulässig als in anderen Namespaces. libmediandk.so und libft2.so werden für den Namespace rs verfügbar gemacht, da libRS_internal.so eine interne Abhängigkeit von diesen Bibliotheken hat.

Abbildung 2: Namespace-Konfiguration für Linker.

Treiber laden

CPU-Fallback-Pfad

Je nachdem, ob das RS_CONTEXT_LOW_LATENCY-Bit beim Erstellen eines RS-Kontexts vorhanden ist, wird entweder der CPU- oder der GPU-Pfad ausgewählt. Wenn der CPU-Pfad ausgewählt ist, wird libRS_internal.so (die Hauptimplementierung des RS-Frameworks) direkt aus dem Standard-Linker-Namespace dlopen, in dem die Plattformversion der RS-Bibliotheken bereitgestellt wird.

Die RS HAL-Implementierung des Anbieters wird überhaupt nicht verwendet, wenn der CPU-Fallback-Pfad verwendet wird, und ein RsContext-Objekt wird mit einem Nullwert für mVendorDriverName erstellt. libRSDriver.so ist (standardmäßig) dlopened und die Treiberbibliothek wird aus dem default-Namespace geladen, da der Aufrufer (libRS_internal.so) ebenfalls im default-Namespace geladen wird.

Abbildung 3: CPU-Fallback-Pfad.

GPU-Pfad

Beim GPU-Pfad wird libRS_internal.so anders geladen. Zuerst verwendet libRS.so android.hardware.renderscript@1.0.so (und die zugrunde liegende libhidltransport.so), um android.hardware.renderscript@1.0-impl.so (eine Anbieterimplementierung der RS HAL) in einen anderen Linker-Namespace namens sphal zu laden. Die RS-HAL dlopent dann libRS_internal.so in einem anderen Linker-Namespace namens rs.

Anbieter können ihren eigenen RS-Treiber bereitstellen, indem sie das Build-Zeit-Flag OVERRIDE_RS_DRIVER festlegen, das in die RS-HAL-Implementierung (hardware/interfaces/renderscript/1.0/default/Context.cpp) eingebettet ist. Dieser Treibername wird dann für den RS-Kontext für den GPU-Pfad dlopened.

Die Erstellung des RsContext-Objekts wird an die RS HAL-Implementierung delegiert. Das HAL ruft das RS-Framework mit der Funktion rsContextCreateVendor() zurück und übergibt den Namen des zu verwendenden Treibers als Argument. Das RS-Framework lädt dann den angegebenen Treiber, wenn RsContext initialisiert wird. In diesem Fall wird die Treiberbibliothek in den Namespace rs geladen, da das Objekt RsContext im Namespace rs erstellt wird und /vendor/lib sich im Suchpfad des Namespace befindet.

Abbildung 4: GPU-Fallback-Pfad

Beim Übergang vom Namespace default zum Namespace sphal verwendet libhidltransport.so die Funktion android_load_sphal_library(), um den dynamischen Linker explizit anzuweisen, die Bibliothek -impl.so aus dem Namespace sphal zu laden.

Beim Übergang vom Namespace sphal zum Namespace rs erfolgt das Laden indirekt über die folgende Zeile in /system/etc/ld.config.txt:

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

In dieser Zeile wird angegeben, dass der dynamische Linker libRS_internal.so aus dem Namespace rs laden soll, wenn die Bibliothek nicht im Namespace sphal gefunden oder geladen werden kann. Das ist immer der Fall, da im Namespace sphal nicht nach /system/lib/vndk-sp gesucht wird, wo sich libRS_internal.so befindet. Mit dieser Konfiguration reicht ein einfacher dlopen()-Aufruf an libRS_internal.so aus, um den Namespace-Übergang durchzuführen.

Bcc-Plug-in laden

bcc plugin ist eine vom Anbieter bereitgestellte Bibliothek, die in den bcc-Compiler geladen wird. Da bcc ein Systemprozess im Verzeichnis /system/bin ist, kann die Bibliothek bcc plugin als SP-HAL (d.h. eine Anbieter-HAL, die direkt in den Systemprozess geladen werden kann, ohne dass sie gebindert werden muss) betrachtet werden. Als SP‑HAL bietet die Bibliothek bcc-plugin:

  • Es kann keine Verknüpfung mit reinen Framework-Bibliotheken wie libLLVM.so hergestellt werden.
  • Es kann nur mit den VNDK-SP-Bibliotheken verknüpft werden, die dem Anbieter zur Verfügung stehen.

Diese Einschränkung wird erzwungen, indem die bcc plugin mit der Funktion android_sphal_load_library() in den Namespace sphal geladen wird. In früheren Versionen von Android wurde der Plug-in-Name mit der Option -load angegeben und die Bibliothek wurde mit dem einfachen dlopen() von libLLVM.so geladen. Unter Android 8.0 und höher wird dies in der Option -plugin angegeben und die Bibliothek wird direkt vom bcc geladen. Diese Option ermöglicht einen nicht Android-spezifischen Pfad zum Open-Source-Projekt LLVM.

Abbildung 5: Das BCC-Plug-in wird geladen (Android 7.x und niedriger).



Abbildung 6 BCC-Plug-in wird geladen (Android 8.0 und höher).

Suchpfade für ld.mc

Bei der Ausführung von ld.mc werden einige RS-Laufzeitbibliotheken als Eingaben für den Linker bereitgestellt. Der RS-Bitcode der App wird mit den Laufzeitbibliotheken verknüpft. Wenn der konvertierte Bitcode in einen App-Prozess geladen wird, werden die Laufzeitbibliotheken wieder dynamisch aus dem konvertierten Bitcode verknüpft.

Zu den Laufzeitbibliotheken gehören:

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • RS-Treiber (entweder libRSDriver.so oder OVERRIDE_RS_DRIVER)

Wenn Sie den kompilierten Bitcode in den App-Prozess laden, stellen Sie genau dieselbe Bibliothek bereit, die von ld.mc verwendet wurde. Andernfalls wird im kompilierten Bitcode möglicherweise ein Symbol nicht gefunden, das beim Verknüpfen verfügbar war.

Dazu verwendet das RS-Framework beim Ausführen von ld.mc unterschiedliche Suchpfade für die Laufzeitbibliotheken, je nachdem, ob das RS-Framework selbst aus /system/lib oder aus /system/lib/vndk-sp geladen wird. Dies kann ermittelt werden, indem die Adresse eines beliebigen Symbols einer RS-Framework-Bibliothek gelesen und dladdr() verwendet wird, um den Dateipfad der Adresse zuzuordnen.

SELinux-Richtlinie

Aufgrund der Änderungen an der SELinux-Richtlinie in Android 8.0 und höher müssen Sie bestimmte Regeln (die durch neverallows erzwungen werden) einhalten, wenn Sie zusätzliche Dateien in der Partition vendor kennzeichnen:

  • vendor_file muss das Standardlabel für alle Dateien in der Partition vendor sein. Gemäß der Plattformrichtlinie ist dies für den Zugriff auf Passthrough-HAL-Implementierungen erforderlich.
  • Alle neuen exec_types, die in der vendor-Partition über die SEPolicy des Anbieters hinzugefügt werden, müssen das Attribut vendor_file_type haben. Dies wird durch neverallows erzwungen.
  • Um Konflikte mit zukünftigen Plattform-/Framework-Updates zu vermeiden, sollten Sie keine Dateien außer exec_types in der Partition vendor kennzeichnen.
  • Alle Bibliotheksabhängigkeiten für AOSP-identifizierte HALs im selben Prozess müssen als same_process_hal_file gekennzeichnet sein.

Weitere Informationen zu SELinux-Richtlinien finden Sie unter Security-Enhanced Linux in Android.

ABI-Kompatibilität für Bitcode

Wenn keine neuen APIs hinzugefügt werden, d. h. keine HAL-Versionserhöhung erfolgt, verwenden die RS-Frameworks weiterhin den vorhandenen GPU-Treiber (HAL 1.0).

Bei geringfügigen HAL-Änderungen (HAL 1.1), die sich nicht auf den Bitcode auswirken, sollten die Frameworks für diese neu hinzugefügten APIs auf die CPU zurückgreifen und an anderer Stelle weiterhin den GPU-Treiber (HAL 1.0) verwenden.

Bei größeren HAL-Änderungen (HAL 2.0), die sich auf die Bitcode-Kompilierung/-Verknüpfung auswirken, sollten RS-Frameworks keine vom Anbieter bereitgestellten GPU-Treiber laden und stattdessen den CPU- oder Vulkan-Pfad für die Beschleunigung verwenden.

Die Verwendung von RenderScript-Bitcode erfolgt in drei Phasen:

Bühne Details
Kompilieren
  • Der Eingabe-Bitcode (.bc) für bcc muss im LLVM 3.2-Bitcodeformat vorliegen und bcc muss abwärtskompatibel mit vorhandenen (Legacy-)Apps sein.
  • Die Metadaten in .bc können sich jedoch ändern (z. B. durch neue Laufzeitfunktionen). Zuweisungs-Setters und -Getters, mathematische Funktionen usw. Ein Teil der Laufzeitfunktionen befindet sich in libclcore.bc, ein Teil in LibRSDriver oder einem entsprechenden Anbieter.
  • Für neue Laufzeitfunktionen oder funktionsgefährdende Metadatenänderungen muss die Bitcode-API-Ebene erhöht werden. Da Anbieter-Treiber sie nicht nutzen können, muss auch die HAL-Version erhöht werden.
  • Anbieter haben möglicherweise eigene Compiler, aber die Schlussfolgerungen/Anforderungen für bcc gelten auch für diese Compiler.
Link
  • Die kompilierte .o-Datei wird mit dem Anbietertreiber verknüpft, z.B.: libRSDriver_foo.so und libcompiler_rt.so. Der CPU-Pfad wird mit libRSDriver.so verknüpft.
  • Wenn für das .o eine neue Laufzeit-API von libRSDriver_foo erforderlich ist, muss der Anbieter-Treiber aktualisiert werden, um sie zu unterstützen.
  • Einige Anbieter haben möglicherweise eigene Linker, aber das Argument für ld.mc gilt auch für sie.
Laden
  • libRSCpuRef lädt das freigegebene Objekt. Wenn es Änderungen an dieser Schnittstelle gibt, ist eine HAL-Versionserhöhung erforderlich.
  • Anbieter würden entweder libRSCpuRef verwenden, um das freigegebene Objekt zu laden, oder eine eigene Implementierung vornehmen.

Neben dem HAL sind auch Runtime-APIs und die exportierten Symbole Schnittstellen. Keine der beiden Schnittstellen hat sich seit Android 7.0 (API 24) geändert und es gibt keine unmittelbaren Pläne, sie in Android 8.0 und höher zu ändern. Wenn sich die Schnittstelle jedoch ändert, wird auch die HAL-Version erhöht.

Anbieterimplementierungen

Unter Android 8.0 und höher sind einige Änderungen am GPU-Treiber erforderlich, damit er richtig funktioniert.

Treibermodule

  • Treibermodule dürfen nicht von Systembibliotheken abhängen, die nicht in der Liste enthalten sind.
  • Der Treiber muss ein eigenes android.hardware.renderscript@1.0-impl_{NAME} bereitstellen oder die Standardimplementierung android.hardware.renderscript@1.0-impl als Abhängigkeit deklarieren.
  • Die CPU-Implementierung libRSDriver.so ist ein gutes Beispiel dafür, wie Nicht-VNDK-SP-Abhängigkeiten entfernt werden können.

Bitcode-Compiler

Sie haben zwei Möglichkeiten, RenderScript-Bitcode für den Anbieter-Treiber zu kompilieren:

  1. Ruft den anbieterspezifischen RenderScript-Compiler in /vendor/bin/ auf (bevorzugte Methode für die GPU-Kompilierung). Ähnlich wie bei anderen Treibermodulen darf die Binärdatei des Anbieter-Compilers nicht von einer Systembibliothek abhängen, die nicht in der Liste der für Anbieter verfügbaren RenderScript-Bibliotheken enthalten ist.
  2. System-BCC aufrufen: /system/bin/bcc mit einem vom Anbieter bereitgestellten bcc plugin. Dieses Plug-in darf nicht von einer Systembibliothek abhängen, die nicht in der Liste der für Anbieter verfügbaren RenderScript-Bibliotheken enthalten ist.

Wenn der Anbieter bcc plugin in die CPU-Kompilierung eingreifen muss und die Abhängigkeit von libLLVM.so nicht einfach entfernt werden kann, sollte der Anbieter bcc (und alle Nicht-LL-NDK-Abhängigkeiten, einschließlich libLLVM.so, libbcc.so) in die Partition /vendor kopieren.

Außerdem müssen Anbieter die folgenden Änderungen vornehmen:

Abbildung 7. Änderungen am Treiber des Anbieters.

  1. Kopieren Sie libclcore.bc in die Partition /vendor. So wird sichergestellt, dass libclcore.bc, libLLVM.so und libbcc.so synchronisiert werden.
  2. Ändern Sie den Pfad zur ausführbaren Datei bcc, indem Sie RsdCpuScriptImpl::BCC_EXE_PATH in der RS HAL-Implementierung festlegen.

SELinux-Richtlinie

Die SELinux-Richtlinie wirkt sich sowohl auf die Treiber- als auch auf die Compiler-Ausführungsdateien aus. Alle Treibermodule müssen im file_contexts des Geräts mit same_process_hal_file gekennzeichnet sein. Beispiel:

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

Die ausführbare Datei des Compilers muss von einem App-Prozess aufgerufen werden können, ebenso wie die Anbieterkopie von bcc (/vendor/bin/bcc). Beispiel:

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

Altgeräte

Als Legacy-Geräte gelten Geräte, die die folgenden Bedingungen erfüllen:

  1. PRODUCT_SHIPPING_API_LEVEL ist niedriger als 26.
  2. PRODUCT_FULL_TREBLE_OVERRIDE ist nicht definiert.

Bei älteren Geräten werden die Einschränkungen beim Upgrade auf Android 8.0 und höher nicht erzwungen. Die Treiber können also weiterhin mit Bibliotheken in /system/lib[64] verknüpft werden. Aufgrund der Architekturänderung im Zusammenhang mit OVERRIDE_RS_DRIVER muss android.hardware.renderscript@1.0-impl jedoch auf der Partition /vendor installiert werden. Andernfalls wird die RenderScript-Laufzeit auf den CPU-Pfad zurückgesetzt.

Informationen zur Motivation für die Einstellung von RenderScript finden Sie im Android Developers Blog unter Android GPU Compute Going Forward. Die Ressourceninformationen für diese Einstellung umfassen Folgendes: