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 zwischen 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 Aufgaben zu planen. RenderScript ist besonders nützlich für Anwendungen, die Bildverarbeitung, computergestützte Fotografie oder maschinelles Sehen 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 interner 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 im Rahmen 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 können entfernt werden). Das würde ein reines Framework-OTA-Verfahren unmöglich machen.

Design

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

Für Anbieter verfügbare RenderScript-Bibliotheken

In diesem Abschnitt werden die RenderScript-Bibliotheken (bekannt als Anbieter NDK für Same-Process-HALs oder VNDK-SP) aufgeführt, die für Anbietercode zur Verfügung stehen und mit denen verknüpft werden können. 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

Linker-Namespace-Konfiguration

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 und 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. Dies ist ein Speicherort, der eine etwas lockerere Erzwingung für RenderScript-Bibliotheken ermöglicht. 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 erlaubt der Namespace rs mehr Bibliotheken, als von anderen Namespaces zur Verfügung gestellt werden. 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 wird, wird libRS_internal.so (die Hauptimplementierung des RS-Frameworks) direkt aus dem Standardverknüpfungs-Namespace, in dem die Plattformversion der RS-Bibliotheken bereitgestellt wird, mit dlopen abgerufen.

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. Der HAL ruft das RS-Framework mithilfe der Funktion rsContextCreateVendor() mit dem Namen des Treibers, der als Argument verwendet werden soll, auf. 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 innerhalb des Namespace rs erstellt wird und sich /vendor/lib im Suchpfad des Namespace befindet.

Abbildung 4 GPU-Fallback-Pfad.

Bei der Umstellung vom Namespace default auf den Namespace sphal verwendet libhidltransport.so die Funktion android_load_sphal_library(), um dem dynamischen Linker explizit zu befehlen, 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-Übergang durchzuführen.

Bcc-Plug-in laden

bcc plugin ist eine vom Anbieter bereitgestellte Bibliothek, die in den bcc-Compiler geladen wird. Da es sich bei bcc um einen Systemprozess im Verzeichnis /system/bin handelt, kann die Bibliothek bcc plugin als SP-HAL betrachtet werden (d.h. als Anbieter-HAL, der direkt in den Systemprozess geladen werden kann, ohne im Bindestrich zu speichern). Als SP-HAL kann die bcc-plugin-Bibliothek Folgendes umfassen:

  • Verknüpfung mit Bibliotheken, die nur für das Framework bestimmt sind, wie libLLVM.so, ist nicht möglich.
  • 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 mithilfe 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. Ab Android 8.0 wird dies in der Option -plugin angegeben und die lib-Bibliothek wird direkt von der bcc selbst 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

Beim Ausführen von ld.mc werden einige RS-Laufzeitbibliotheken als Eingaben an die Verknüpfung übergeben. Der RS-Bitcode der Anwendung wird mit den Laufzeitbibliotheken verknüpft. Wenn der konvertierte Bitcode in einen Anwendungsprozess geladen wird, werden die Laufzeitbibliotheken wieder dynamisch vom konvertierten Bitcode verknüpft.

Zu den Laufzeitbibliotheken gehören:

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • RS-Fahrer (entweder 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 der SELinux-Richtlinie in Android 8.0 und höher müssen Sie beim Hinzufügen von Labels zu zusätzlichen Dateien in der Partition vendor bestimmte Regeln befolgen (durchgeführt durch neverallows):

  • 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 Dateien in der Partition vendor nicht mit anderen Labels als exec_types versehen.
  • 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 ihn 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 ist 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. Bei Änderungen an dieser Schnittstelle ist eine Erhöhung der HAL-Version erforderlich.
  • Anbieter müssen das freigegebene Objekt entweder über libRSCpuRef laden oder ein eigenes implementieren.

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

Implementierungen von Anbietern

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.

Darüber hinaus müssen Anbieter folgende Änderungen vornehmen:

Abbildung 7. Änderungen am Anbietertreiber.

  1. Kopieren Sie libclcore.bc in die Partition /vendor. Dadurch wird sichergestellt, dass libclcore.bc, libLLVM.so und libbcc.so synchron sind.
  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 die Treiber als auch auf die ausführbaren Compiler-Dateien aus. Alle Treibermodule müssen in der 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 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 aufgrund von OVERRIDE_RS_DRIVER muss android.hardware.renderscript@1.0-impl jedoch auf der Partition /vendor installiert werden. Andernfalls wird das RenderScript-Laufzeit-Fallback auf den CPU-Pfad erzwungen.

Informationen zur Beweggründe für die Einstellung von Renderscript finden Sie im Blog für Android-Entwickler: Android GPU Compute Going Forward. Zu den Ressourceninformationen für diese Einstellung gehören: