RenderScript

RenderScript ist ein Framework zum Ausführen rechenintensiver Aufgaben mit hoher Leistung auf Android-Geräten. Sie wurde für die Verwendung mit datenparrallel arbeitenden Berechnungen entwickelt, kann aber auch für serielle Arbeitslasten genutzt werden. Die RenderScript-Laufzeit parallelisiert die Arbeit auf allen auf einem Gerät verfügbaren Prozessoren, z. B. auf Mehrkern-CPUs und GPUs. So können sich Entwickler darauf konzentrieren, Algorithmen zu erstellen, anstatt Aufgaben zu planen. RenderScript ist besonders nützlich für Apps, die Bildverarbeitung, Computerfotografie oder Computer Vision nutzen.

Auf Geräten mit Android 8.0 und höher werden das folgende RenderScript-Framework und die folgenden HALs von Anbietern verwendet:

Abbildung 1: Anbietercode, der mit internen libs verknüpft ist.

Zu den Unterschieden zu RenderScript in Android 7.x und niedriger gehören:

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

Design

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

RenderScript-Bibliotheken für Anbieter verfügbar

In diesem Abschnitt sind die RenderScript-Bibliotheken (Vendor NDK for Same-Process HALs oder VNDK-SP) aufgeführt, die für Anbietercode verfügbar sind und mit denen eine Verknüpfung hergestellt werden kann. Außerdem werden zusätzliche Bibliotheken aufgeführt, die nichts mit RenderScript zu tun haben, aber auch für Anbietercode bereitgestellt werden.

Die folgende Liste der Bibliotheken kann sich zwischen Android-Releases unterscheiden, ist aber für einen bestimmten 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

Konfiguration des Linker-Namespaces

Die Verknüpfungsbeschränkung, die verhindert, dass ‑Libs, 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 einem Gerät mit Android 8.0 oder höher werden alle SP-HALs (Same-Process HALs, HALs mit demselben Prozess) mit Ausnahme von RenderScript im Linker-Namespace sphal geladen. RenderScript wird in den RenderScript-spezifischen Namespace rs geladen. An diesem Speicherort ist die Durchsetzung für RenderScript-Bibliotheken etwas lockerer. 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 Bibliothken aus der Datenpartition laden.

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

Abbildung 2: Namespace-Konfiguration für den 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 Standardlinker-Namespace dlopened, in dem die Plattformversion der RS-Bibliotheken bereitgestellt wird.

Die RS HAL-Implementierung des Anbieters wird nicht verwendet, wenn der CPU-Fallbackpfad verwendet wird, und ein RsContext-Objekt wird mit null mVendorDriverName erstellt. libRSDriver.so wird standardmäßig dlopened und die Treiberbibliothek wird aus dem Namespace default geladen, da auch der Aufrufer (libRS_internal.so) im Namespace default geladen wird.

Abbildung 3: CPU-Fallback-Pfad.

GPU-Pfad

Für den GPU-Pfad wird die 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 dlopens libRS_internal.so dann in einem anderen Linker-Namespace namens rs.

Anbieter können ihren eigenen RS-Treiber bereitstellen, indem sie das Buildzeit-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. Die HAL ruft das RS-Framework mit der Funktion rsContextCreateVendor() auf und übergibt den Namen des 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 RsContext-Objekt im Namespace rs erstellt wird und /vendor/lib sich im Suchpfad des Namespace befindet.

Abbildung 4: GPU-Fallback-Pfad.

Bei der Umstellung vom Namespace default auf den Namespace sphal weist libhidltransport.so den dynamischen Linker über die Funktion android_load_sphal_library() ausdrücklich an, die -impl.so-Bibliothek 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. Bei dieser Konfiguration reicht ein einfacher dlopen()-Aufruf an libRS_internal.so aus, um den Namespace zu wechseln.

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 bcc plugin-Bibliothek als SP-HAL (d.h. als HAL eines Anbieters, die direkt in den Systemprozess geladen werden kann, ohne verbunden zu werden) betrachtet werden. Als SP-HAL bietet die bcc-plugin-Bibliothek folgende Vorteile:

  • Es ist keine Verknüpfung mit Bibliotheken möglich, die nur für das Framework bestimmt sind, z. B. libLLVM.so.
  • Es kann nur mit den VNDK-SP-Bibliotheken verknüpft werden, die dem Anbieter zur Verfügung stehen.

Diese Einschränkung wird erzwungen, indem 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 Lib 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 Lib wird direkt von bcc geladen. Mit dieser Option wird ein nicht Android-spezifischer Pfad zum Open-Source-LLVM-Projekt aktiviert.

Abbildung 5: bcc-Plug-in wird geladen, Android 7.x und niedriger



Abbildung 6 Laden des BCC-Plug-ins, Android 8.0 und höher

Suchpfade für ld.mc

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

Zu den Laufzeitbibliotheken gehören:

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

Wenn Sie den kompilierten Bitcode in den App-Prozess laden, müssen Sie genau dieselbe Bibliothek angeben, die von ld.mc verwendet wurde. Andernfalls wird im kompilierten Bitcode möglicherweise kein Symbol gefunden, das bei der Verknüpfung 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 von /system/lib oder von /system/lib/vndk-sp geladen wird. Dazu wird die Adresse eines beliebigen Symbols einer RS-Framework-Bibliothek gelesen und mit dladdr() der Dateipfad abgerufen, der der Adresse zugeordnet ist.

SELinux-Richtlinie

Aufgrund der Änderungen an den SELinux-Richtlinien in Android 8.0 und höher müssen Sie beim Beschriften zusätzlicher Dateien in der vendor-Partition bestimmte Regeln einhalten, die über neverallows erzwungen werden:

  • vendor_file muss das Standardlabel für alle Dateien in der vendor-Partition sein. Gemäß der Plattformrichtlinie ist dies für den Zugriff auf Passthrough-HAL-Implementierungen erforderlich.
  • Alle neuen exec_types, die über die SEPolicy des Anbieters der vendor-Partition hinzugefügt werden, müssen das Attribut vendor_file_type haben. Dies wird über neverallows erzwungen.
  • Um Konflikte mit zukünftigen Plattform-/Framework-Updates zu vermeiden, sollten Sie in der Partition vendor keine anderen Dateien als exec_types kennzeichnen.
  • Alle Bibliotheksabhängigkeiten für von AOSP identifizierte HALs für denselben 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-Version erhöht wird, 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 den GPU-Treiber (HAL 1.0) an anderer Stelle weiter 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, sondern 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 Bitcode-Format LLVM 3.2 vorliegen und bcc muss abwärtskompatibel mit vorhandenen (alten) Apps sein.
  • Die Metadaten in .bc können sich jedoch ändern (z.B. neue Laufzeitfunktionen, Zuweisungs-Setter und -Getter, mathematische Funktionen usw.). Ein Teil der Laufzeitfunktionen befindet sich in libclcore.bc, ein Teil in LibRSDriver oder einem vergleichbaren Anbietertool.
  • Neue Laufzeitfunktionen oder bahnbrechende Metadatenänderungen erfordern eine Erhöhung der Bitcode-API-Ebene. Da Anbietertreiber diese 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 Treiber des Anbieters verknüpft, z.B. libRSDriver_foo.so und libcompiler_rt.so. Der CPU-Pfad wird mit libRSDriver.so verknüpft.
  • Wenn für die .o-Datei eine neue Laufzeit-API von libRSDriver_foo erforderlich ist, muss der Anbietertreiber aktualisiert werden, um sie zu unterstützen.
  • Bestimmte 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 sich diese Schnittstelle ändert, ist eine Erhöhung der HAL-Version erforderlich.
  • Anbieter würden entweder libRSCpuRef zum Laden des freigegebenen Objekts verwenden oder ein eigenes implementieren.

Neben der HAL sind auch die Laufzeit-APIs und die exportierten Symbole Schnittstellen. Die Benutzeroberfläche hat sich seit Android 7.0 (API 24) nicht geändert und es gibt keine unmittelbaren Pläne, sie in Android 8.0 und höher zu ändern. Wenn sich die Benutzeroberfläche 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 ordnungsgemäß funktioniert.

Treibermodule

  • Treibermodule dürfen nicht von Systembibliotheken abhängen, die nicht in der Liste enthalten sind.
  • Der Treiber muss eine eigene 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 Sie Abhängigkeiten, die nicht zu VNDK-SP gehören, entfernen.

Bitcode-Compiler

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

  1. Anbieterspezifischen RenderScript-Compiler in /vendor/bin/ aufrufen (bevorzugte Methode der GPU-Kompilierung) Ähnlich wie bei anderen Treibermodulen darf das Binärprogramm des Anbietercompilers nicht von einer Systembibliothek abhängen, die nicht in der Liste der für Anbieter verfügbaren RenderScript-Bibliotheken enthalten ist.
  2. System-bcc: /system/bin/bcc mit einer vom Anbieter bereitgestellten bcc plugin aufrufen; 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 seine Abhängigkeit von libLLVM.so nicht einfach entfernt werden kann, sollte er 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 Anbietertreiber.

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

SELinux-Richtlinie

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

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

Die ausführbare Compilerdatei 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

Ältere Geräte

Zu den Legacy-Geräten gehören Geräte, die die folgenden Bedingungen erfüllen:

  1. PRODUCT_SHIPPING_API_LEVEL ist kleiner 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. Das bedeutet, dass die Treiber weiterhin mit Bibliotheken in /system/lib[64] verknüpft werden können. Aufgrund der Architekturänderung im Zusammenhang mit OVERRIDE_RS_DRIVER muss android.hardware.renderscript@1.0-impl jedoch in der Partition /vendor installiert werden. Andernfalls wird die RenderScript-Laufzeit auf den CPU-Pfad zurückgesetzt.

Informationen zu den Gründen für die Einstellung von Renderscript finden Sie im Android Developers-Blog: Android GPU Compute Going Forward. Zu den Ressourceninformationen für diese Einstellung gehören: