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 sekwencyjnie. Ś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/libsą tworzone w ramach platformy i aktualizowane wraz zsystem.img. Biblioteki w/system/lib/vndk-spsą jednak tworzone dla dostawcy i nie są aktualizowane podczas uaktualnianiasystem.img(mogą być aktualizowane w celu poprawienia zabezpieczeń, ale ich interfejs 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
W tej sekcji znajdziesz 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 |
|---|---|
|
|
Konfiguracja przestrzeni nazw tagu łączącego
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 RenderScript i umożliwia nieco mniej rygorystyczne egzekwowanie zasad w przypadku bibliotek RenderScript. Implementacja RS musi wczytać skompilowany kod pośredni, więc do ścieżki przestrzeni nazw rs dodawany jest element /data/*/*.so (inne interfejsy 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. Użytkownicy libmediandk.so i libft2.so
mają dostęp do przestrzeni nazw rs, ponieważ
libRS_internal.so ma wewnętrzną zależność od tych bibliotek.
Rysunek 2. Konfiguracja przestrzeni nazw dla linkera.
Wczytywanie sterowników
Ś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) do wczytywania android.hardware.renderscript@1.0-impl.so (implementacji RS HAL dostawcy) do innej przestrzeni nazw linkera o nazwie sphal. RS
HAL następnie 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 framework RS za pomocą funkcji rsContextCreateVendor() z nazwą sterownika, który ma być używany jako argument. Po zainicjowaniu RsContext platforma RS wczytuje określony sterownik. 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ę bcc
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 załadować do procesu systemowego bez użycia mechanizmu Binder). Jako SP-HAL biblioteka bcc-plugin:
- Nie można łączyć z bibliotekami zawierającymi tylko struktury, takimi jak
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, który nie jest przeznaczony dla 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.solibm.solibc.so- Sterownik RS (
libRSDriver.solubOVERRIDE_RS_DRIVER)
Podczas wczytywania skompilowanego kodu bitowego do procesu aplikacji podaj dokładnie tę samą bibliotekę, która została użyta przez ld.mc. W przeciwnym razie skompilowany kod bitowy 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 platformy 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 na partycji vendor musisz przestrzegać określonych reguł (egzekwowanych za pomocą neverallows):
vendor_filemusi być etykietą domyślną dla wszystkich plików wvendorpartycji. Zasady platformy wymagają tego, aby uzyskać dostęp do implementacji HAL typu passthrough.- Wszystkie nowe
exec_typesdodane wvendorpartycji za pomocą zasad SEPolicy dostawcy muszą mieć atrybutvendor_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_typesw partycjivendor. - 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ść ABI w przypadku kodu bitowego
Jeśli nie zostaną dodane żadne nowe interfejsy API, co oznacza brak zmiany wersji HAL, platformy RS będą nadal korzystać z istniejącego 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łączyć 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 bitowego platformy RS nie powinny wczytywać sterowników GPU dostarczonych przez dostawcę, ale zamiast tego używać ścieżki procesora lub Vulkan do akceleracji.
Korzystanie z kodu bajtowego RenderScript odbywa się w 3 etapach:
| Etap | Szczegóły |
|---|---|
| Kompilacja |
|
| Link |
|
| Wczytaj |
|
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 nowszych. 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-impljako zależność. - Implementacja procesora
libRSDriver.sojest dobrym przykładem tego, jak usunąć zależności inne niż VNDK-SP.
Kompilator kodu bitowego
Kod bitowy RenderScript dla sterownika dostawcy możesz skompilować na 2 sposoby:
- 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. - Wywołaj system bcc:
/system/bin/bccz dostarczonym przez dostawcębcc plugin; ten wtyk 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.
- Kopiowanie
libclcore.bcna partycję/vendor. Dzięki temulibclcore.bc,libLLVM.soilibbcc.sosą zsynchronizowane. - Zmień ścieżkę do pliku wykonywalnego
bcc, ustawiającRsdCpuScriptImpl::BCC_EXE_PATHw 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_file w file_contexts urządzenia. 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
Starsze urządzenia
Starsze urządzenia to te, które spełniają te warunki:
- Wartość PRODUCT_SHIPPING_API_LEVEL jest mniejsza niż 26.
- 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 w /vendor partycji. Jeśli tego nie zrobisz, środowisko wykonawcze RenderScript będzie musiało użyć ścieżki procesora.
Informacje o przyczynach wycofania Renderscript znajdziesz na blogu dla deweloperów Androida: Android GPU Compute Going Forward (w języku angielskim). Informacje o wycofaniu tego zasobu obejmują:
- Migracja z Renderscript
- Przykład migracji RenderScript
- Zestaw narzędzi do zastępowania funkcji wewnętrznych README
- Intrinsics ReplacementToolkit.kt