RenderScript

RenderScript to platforma do uruchamiania na Androidzie zadań wymagających dużej mocy obliczeniowej z wysoką wydajnością. Jest on przeznaczony do obliczeń równoległych na danych, ale może być też przydatny w przypadku zadań wykonywanych szeregowo. Środowisko wykonawcze RenderScriptu równolegle przetwarza zadania na procesorach dostępnych na urządzeniu, takich jak wielordzeniowe procesory CPU i GPU, dzięki czemu deweloperzy mogą skupić się na wyrażaniu algorytmów, a nie na planowaniu pracy. RenderScript jest szczególnie przydatny w przypadku aplikacji, które przetwarzają obrazy, wykonują obliczenia fotograficzne lub korzystają z widzenia komputerowego.

Urządzenia z Androidem 8.0 i nowszym korzystają z tych platform RenderScript i HAL dostawców:

Rysunek 1. Kod dostawcy łączący się z bibliotekami wewnętrznymi.

Różnice w stosunku do RenderScript w Androidzie 7.x i starszych wersjach:

  • Dwie instancje wewnętrznych bibliotek RenderScript w procesie. Jeden zestaw jest przeznaczony dla ścieżki rezerwowej procesora i pochodzi bezpośrednio z /system/lib, a drugi zestaw jest przeznaczony dla ścieżki procesora graficznego i pochodzi z /system/lib/vndk-sp.
  • Wewnętrzne biblioteki RS w /system/lib są tworzone w ramach platformy i aktualizowane wraz z system.img. Biblioteki w /system/lib/vndk-sp są jednak tworzone dla dostawcy i nie są aktualizowane podczas uaktualniania system.img (mogą być aktualizowane w celu poprawienia zabezpieczeń, ale ich ABI pozostaje taki sam).
  • Kod dostawcy (RS HAL, sterownik RS i bcc plugin) jest połączony z wewnętrznymi bibliotekami RenderScript znajdującymi się w /system/lib/vndk-sp. Nie mogą one łączyć się z bibliotekami w /system/lib, ponieważ biblioteki w tym katalogu są przeznaczone na platformę i mogą nie być zgodne z kodem dostawcy (np. symbole mogą zostać usunięte). Uniemożliwiłoby to aktualizację OTA tylko z platformą.

Projektowanie

W kolejnych sekcjach znajdziesz szczegółowe informacje o architekturze RenderScript w Androidzie 8.0 i nowszych wersjach.

Biblioteki RenderScript dostępne dla dostawców

Ta sekcja zawiera listę bibliotek RenderScript (znanych jako Vendor NDK for Same-Process HALs lub VNDK-SP), które są dostępne dla kodu dostawcy i z którymi można się łączyć. Opisuje też dodatkowe biblioteki, które nie są związane z RenderScriptem, ale są też udostępniane w kodzie dostawcy.

Poniższa lista bibliotek może się różnić w zależności od wersji Androida, ale w przypadku konkretnej wersji Androida jest niezmienna. Aktualną listę dostępnych bibliotek znajdziesz w /system/etc/ld.config.txt.

Biblioteki RenderScript Biblioteki inne niż 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

Konfiguracja przestrzeni nazw tagu łączącego konwersje

Ograniczenie łączenia, które uniemożliwia używanie bibliotek spoza VNDK-SP przez kod dostawcy, jest egzekwowane w czasie działania za pomocą przestrzeni nazw linkera. (Więcej informacji znajdziesz w prezentacji VNDK Design).

Na urządzeniach z Androidem 8.0 i nowszym wszystkie interfejsy HAL tego samego procesu (SP-HAL) z wyjątkiem RenderScript są ładowane w przestrzeni nazw linkerasphal. RenderScript jest ładowany do przestrzeni nazw rs, która jest przeznaczona dla RenderScriptu i umożliwia nieco mniej rygorystyczne egzekwowanie zasad w przypadku bibliotek RenderScriptu. Implementacja RS musi wczytać skompilowany kod pośredni, dlatego do ścieżki przestrzeni nazw rs dodawany jest element /data/*/*.so (inne SP-HAL nie mogą wczytywać bibliotek z partycji danych).

Dodatkowo przestrzeń nazw rs umożliwia korzystanie z większej liczby bibliotek niż inne przestrzenie nazw. libmediandk.solibft2.so są udostępniane w przestrzeni nazw rs, ponieważ libRS_internal.so ma wewnętrzną zależność od tych bibliotek.

Rysunek 2. Konfiguracja przestrzeni nazw dla linkera.

Czynniki obciążenia

Ścieżka rezerwowa procesora

W zależności od tego, czy podczas tworzenia kontekstu RS istnieje bit RS_CONTEXT_LOW_LATENCY, wybierana jest ścieżka procesora lub procesora graficznego. Gdy wybrana jest ścieżka procesora, libRS_internal.so (główna implementacja struktury RS) jest bezpośrednio dlopenowana z domyślnej przestrzeni nazw linkera, w której udostępniana jest wersja platformy bibliotek RS.

Implementacja RS HAL dostawcy nie jest w ogóle używana, gdy wybierana jest ścieżka rezerwowa CPU, a obiekt RsContext jest tworzony z wartością null mVendorDriverName. libRSDriver.so jest (domyślnie) dlopened, a biblioteka sterownika jest wczytywana z przestrzeni nazw default, ponieważ wywołujący (libRS_internal.so) jest również wczytywany w przestrzeni nazw default.

Rysunek 3. Ścieżka rezerwowa procesora.

Ścieżka GPU

W przypadku ścieżki GPU element libRS_internal.so jest wczytywany inaczej. Po pierwsze, libRS.so używa android.hardware.renderscript@1.0.so (i jego bazowego libhidltransport.so), aby wczytać android.hardware.renderscript@1.0-impl.so (implementację RS HAL dostawcy) do innej przestrzeni nazw linkera o nazwie sphal. Interfejs HAL RS dlopens libRS_internal.so w innej przestrzeni nazw linkera o nazwie rs.

Dostawcy mogą udostępniać własny sterownik RS, ustawiając flagę czasu kompilacji OVERRIDE_RS_DRIVER, która jest osadzona w implementacji RS HAL (hardware/interfaces/renderscript/1.0/default/Context.cpp). Nazwa tego sterownika jest następnie dlopenana w kontekście RS na potrzeby ścieżki GPU.

Tworzenie obiektu RsContext jest delegowane do implementacji RS HAL. HAL wywołuje zwrotnie platformę RS za pomocą funkcji rsContextCreateVendor(), podając jako argument nazwę sterownika, który ma być używany. Framework RS wczytuje następnie określony sterownik po zainicjowaniu RsContext. W tym przypadku biblioteka sterownika jest ładowana do przestrzeni nazw rs, ponieważ obiekt RsContext jest tworzony w przestrzeni nazw rs, a /vendor/lib znajduje się w ścieżce wyszukiwania przestrzeni nazw.

Rysunek 4. Ścieżka rezerwowa GPU.

Podczas przechodzenia z przestrzeni nazw default do przestrzeni nazw sphal funkcja libhidltransport.so używa funkcji android_load_sphal_library(), aby jawnie nakazać dynamicznemu linkerowi załadowanie biblioteki -impl.so z przestrzeni nazw sphal.

Podczas przechodzenia z przestrzeni nazw sphal do przestrzeni nazw rs wczytywanie odbywa się pośrednio za pomocą tego wiersza w /system/etc/ld.config.txt:

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

Ten wiersz określa, że dynamiczny linker powinien wczytać libRS_internal.so z przestrzeni nazw rs, gdy nie można znaleźć lub wczytać biblioteki z przestrzeni nazw sphal (co zawsze ma miejsce, ponieważ przestrzeń nazw sphal nie przeszukuje /system/lib/vndk-sp, w której znajduje się libRS_internal.so). W tej konfiguracji wystarczy proste wywołanie dlopen() do libRS_internal.so, aby dokonać przejścia przestrzeni nazw.

Wczytaj wtyczkę UDW

bcc plugin to biblioteka dostarczona przez dostawcę, która jest wczytywana do kompilatora bcc. Ponieważ bcc jest procesem systemowym w katalogu /system/bin, bibliotekę bcc plugin można uznać za SP-HAL (czyli HAL dostawcy, który można bezpośrednio wczytać do procesu systemowego bez użycia mechanizmu Binder). Jako SP-HAL biblioteka bcc-plugin:

  • Nie można łączyć z bibliotekami, które są przeznaczone tylko dla platform, np. libLLVM.so.
  • Może łączyć się tylko z bibliotekami VNDK-SP dostępnymi dla dostawcy.

To ograniczenie jest egzekwowane przez załadowanie bcc plugin do przestrzeni nazw sphal za pomocą funkcji android_sphal_load_library(). W poprzednich wersjach Androida nazwa wtyczki była określana za pomocą opcji -load, a biblioteka była wczytywana za pomocą prostego polecenia dlopen() przez libLLVM.so. W Androidzie 8.0 i nowszym jest to określone w opcji -plugin, a biblioteka jest bezpośrednio wczytywana przez bcc. Ta opcja umożliwia dostęp do projektu open source LLVM w sposób niezależny od Androida.

Rysunek 5. Ładowanie wtyczki bcc, Android 7.x i starsze.



Rysunek 6. Wczytywanie wtyczki bcc, Android 8.0 lub nowszy.

Ścieżki wyszukiwania dla ld.mc

Podczas wykonywania ld.mc niektóre biblioteki środowiska wykonawczego RS są przekazywane do linkera jako dane wejściowe. Kod bitowy RS z aplikacji jest połączony z bibliotekami środowiska wykonawczego, a gdy przekonwertowany kod bitowy jest wczytywany do procesu aplikacji, biblioteki środowiska wykonawczego są ponownie dynamicznie łączone z przekonwertowanym kodem bitowym.

Biblioteki środowiska wykonawczego obejmują:

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • Sterownik RS (libRSDriver.so lub OVERRIDE_RS_DRIVER)

Podczas wczytywania skompilowanego kodu pośredniego do procesu aplikacji podaj dokładnie tę samą bibliotekę, która została użyta przez ld.mc. W przeciwnym razie skompilowany kod pośredni może nie znaleźć symbolu, który był dostępny podczas łączenia.

W tym celu platforma RS używa różnych ścieżek wyszukiwania bibliotek środowiska wykonawczego podczas wykonywania ld.mc, w zależności od tego, czy sama platforma RS jest wczytywana z /system/lib czy z /system/lib/vndk-sp. Można to ustalić, odczytując adres dowolnego symbolu biblioteki RS i używając dladdr(), aby uzyskać ścieżkę pliku mapowaną na adres.

Zasady SELinux

W wyniku zmian w zasadach SELinux w Androidzie 8.0 i nowszych podczas oznaczania dodatkowych plików w vendor musisz przestrzegać określonych reguł (egzekwowanych za pomocą neverallows):

  • vendor_file musi być domyślną etykietą wszystkich plików w vendor partycji. Zasady platformy wymagają tego, aby uzyskać dostęp do implementacji HAL typu passthrough.
  • Wszystkie nowe exec_types dodane w vendor partycji za pomocą zasad SEPolicy dostawcy muszą mieć atrybut vendor_file_type. Jest to egzekwowane za pomocą neverallows.
  • Aby uniknąć konfliktów z przyszłymi aktualizacjami platformy lub struktury, nie oznaczaj plików innych niż exec_typesvendor.
  • Wszystkie zależności biblioteki w przypadku zidentyfikowanych przez AOSP interfejsów HAL działających w tym samym procesie muszą być oznaczone jako same_process_hal_file.

Więcej informacji o zasadach SELinux znajdziesz w artykule Security-Enhanced Linux w Androidzie.

Zgodność interfejsu ABI z kodem bitowym

Jeśli nie zostaną dodane żadne nowe interfejsy API, co oznacza, że nie nastąpi zmiana wersji HAL, platformy RS będą nadal korzystać z dotychczasowego sterownika GPU (HAL 1.0).

W przypadku drobnych zmian w HAL (HAL 1.1), które nie mają wpływu na kod pośredni, platformy powinny w przypadku tych nowo dodanych interfejsów API przełączać się na procesor i w innych przypadkach nadal używać sterownika GPU (HAL 1.0).

W przypadku poważnych zmian w HAL (HAL 2.0) wpływających na kompilację/łączenie kodu pośredniego platformy RS powinny zrezygnować z wczytywania sterowników GPU dostarczonych przez dostawcę i zamiast tego używać ścieżki CPU lub Vulkan do akceleracji.

Korzystanie z kodu bajtowego RenderScript odbywa się w 3 etapach:

Etap Szczegóły
Kompiluj
  • Kod pośredni (.bc) dla bcc musi mieć format kodu pośredniego LLVM 3.2, a bcc musi być wstecznie zgodny z dotychczasowymi (starszymi) aplikacjami.
  • Metadane w pliku .bc mogą się jednak zmienić (mogą pojawić się nowe funkcje środowiska wykonawczego, np. Ustawienia i pobieranie alokacji, funkcje matematyczne itp. Część funkcji środowiska wykonawczego znajduje się w libclcore.bc, a część w bibliotece LibRSDriver lub jej odpowiedniku dostarczonym przez producenta.
  • Nowe funkcje środowiska wykonawczego lub istotne zmiany w metadanych wymagają zwiększenia poziomu interfejsu API kodu bajtowego. Sterowniki dostawcy nie będą mogły z niej korzystać, dlatego należy też zwiększyć numer wersji HAL.
  • Dostawcy mogą mieć własne kompilatory, ale wnioski i wymagania dotyczące bcc obowiązują również w przypadku tych kompilatorów.
Link
  • Skompilowany plik .o zostanie połączony ze sterownikiem dostawcy, np. libRSDriver_foo.solibcompiler_rt.so. Ścieżka CPU będzie połączona z libRSDriver.so.
  • Jeśli plik .o wymaga nowego interfejsu API środowiska wykonawczego od libRSDriver_foo, sterownik dostawcy musi zostać zaktualizowany, aby go obsługiwać.
  • Niektórzy dostawcy mogą mieć własne linkery, ale argumenty za ld.mc dotyczą też ich.
Wczytaj
  • libRSCpuRef wczytuje udostępniony obiekt. Jeśli w tym interfejsie zostaną wprowadzone zmiany, konieczna będzie aktualizacja wersji HAL.
  • Dostawcy będą korzystać z libRSCpuRef do wczytywania udostępnionego obiektu lub implementować własne rozwiązanie.

Oprócz HAL interfejsami są też interfejsy API środowiska wykonawczego i eksportowane symbole. Żaden z tych interfejsów nie zmienił się od Androida 7.0 (API 24) i nie planujemy wprowadzać w nich zmian w Androidzie 8.0 ani w nowszych wersjach. Jeśli jednak interfejs ulegnie zmianie, wersja HAL również zostanie zwiększona.

Implementacje dostawców

Android 8.0 i nowsze wersje wymagają wprowadzenia pewnych zmian w sterowniku GPU, aby działał on prawidłowo.

Moduły sterownika

  • Moduły sterownika nie mogą zależeć od żadnych bibliotek systemowych, które nie znajdują się na liście.
  • Sterownik musi udostępniać własną android.hardware.renderscript@1.0-impl_{NAME} lub deklarować domyślną implementację android.hardware.renderscript@1.0-impl jako zależność.
  • Implementacja procesora libRSDriver.so to dobry przykład usuwania zależności innych niż VNDK-SP.

Kompilator kodu bitowego

Kod bitowy RenderScript dla sterownika dostawcy możesz skompilować na 2 sposoby:

  1. Wywołaj kompilator RenderScript specyficzny dla dostawcy w /vendor/bin/ (preferowana metoda kompilacji GPU). Podobnie jak inne moduły sterownika, binarny kompilator dostawcy nie może zależeć od żadnej biblioteki systemowej, która nie znajduje się na liście bibliotek RenderScript dostępnych dla dostawców.
  2. Wywołaj system bcc: /system/bin/bcc z dostarczonym przez dostawcę bcc plugin; ten wtyczka nie może zależeć od żadnej biblioteki systemowej, która nie znajduje się na liście bibliotek RenderScript dostępnych dla dostawców.

Jeśli dostawca bcc plugin musi ingerować w kompilację procesora i nie można łatwo usunąć jego zależności od libLLVM.so, powinien skopiować bcc (i wszystkie zależności inne niż LL-NDK, w tym libLLVM.so, libbcc.so) do partycji /vendor.

Dostawcy muszą też wprowadzić te zmiany:

Rysunek 7. Zmiany w sterowniku dostawcy.

  1. Kopiuj libclcore.bc do partycji /vendor. Dzięki temu libclcore.bc, libLLVM.so i libbcc.so są zsynchronizowane.
  2. Zmień ścieżkę do pliku wykonywalnego bcc, ustawiając RsdCpuScriptImpl::BCC_EXE_PATH w implementacji RS HAL.

Zasady SELinux

Zasady SELinux mają wpływ zarówno na sterownik, jak i na pliki wykonywalne kompilatora. Wszystkie moduły sterownika muszą być oznaczone symbolem same_process_hal_filefile_contexts urządzenia. Na przykład:

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

Wykonywalny plik kompilatora musi być wywoływany przez proces aplikacji, podobnie jak kopia bcc dostawcy (/vendor/bin/bcc). Przykład:

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

Urządzenia starszego typu

Urządzenia starszego typu to te, które spełniają te warunki:

  1. PRODUCT_SHIPPING_API_LEVEL jest mniejszy niż 26.
  2. Wartość PRODUCT_FULL_TREBLE_OVERRIDE nie jest zdefiniowana.

W przypadku starszych urządzeń ograniczenia nie są wymuszane podczas aktualizacji do Androida 8.0 lub nowszego, co oznacza, że sterowniki mogą nadal łączyć się z bibliotekami w /system/lib[64]. Jednak ze względu na zmianę architektury związaną z OVERRIDE_RS_DRIVER należy zainstalować android.hardware.renderscript@1.0-impl/vendor partycji. W przeciwnym razie środowisko wykonawcze RenderScript będzie musiało wrócić do ścieżki procesora.

Informacje o przyczynach wycofania Renderscript znajdziesz na blogu dla deweloperów aplikacji na Androida: Android GPU Compute Going Forward (w języku angielskim). Informacje o zasobach dotyczące tego wycofania obejmują: