RenderScript to framework do wykonywania zadań wymagających dużej mocy obliczeniowej na urządzeniach z Androidem. Jest on przeznaczony do korzystania z obliczeń równoległych z danymi, ale może też przynieść korzyści w przypadku zadań sekwencyjnych. Środowisko wykonawcze RenderScript działa równolegle na różnych procesorach dostępnych w urządzeniu, takich jak procesory wielordzeniowe i GPU, dzięki czemu deweloperzy mogą skupić się na prezentowaniu algorytmów, a nie na planowaniu pracy. Skrypt RenderScript jest szczególnie przydatny w aplikacjach służących do przetwarzania obrazu, fotografii obliczeniowej lub rozpoznawania obrazów.
Urządzenia z Androidem 8.0 lub nowszym korzystają z następującego frameworku RenderScript i interfejsów HAL dostawców:
Rysunek 1. Kod dostawcy łączący się z bibliotekami wewnętrznymi.
Różnice między RenderScript w Androidzie 7.x i starszych wersjach:
- 2 instancje bibliotek wewnętrznych RenderScript w procesie. Jeden zestaw jest przeznaczony do ścieżki awaryjnej procesora i jest bezpośrednio z
/system/lib
; drugi zestaw jest przeznaczony do ścieżki GPU i jest z/system/lib/vndk-sp
. - Biblioteki wewnętrzne RS w
/system/lib
są tworzone jako część platformy i aktualizowane wraz z uaktualnianiemsystem.img
. Biblioteki w/system/lib/vndk-sp
są jednak tworzone dla dostawcy i nie są aktualizowane po uaktualnieniusystem.img
(chociaż można je zaktualizować pod kątem poprawki zabezpieczeń, interfejs ABI pozostaje bez zmian). - Kod dostawcy (RS HAL, sterownik RS i
bcc plugin
) jest połączony z wewnętrznymi bibliotekami RenderScript na stronie/system/lib/vndk-sp
. Nie można ich łączyć z bibliotekami w katalogu/system/lib
, ponieważ są one tworzone dla danej platformy i mogą nie być zgodne z kodem dostawcy (np. symbole mogą zostać usunięte). W przeciwnym razie byłoby to niemożliwe.
Projektowanie
W następnych sekcjach znajdziesz szczegółowe informacje o projektowaniu RenderScript w Androidzie 8.0 i nowszych wersjach.
Biblioteki RenderScript dostępne dla dostawców
W tej sekcji wymieniono biblioteki RenderScript (znane jako NDK dostawcy dla interfejsów HAL w ramach tego samego procesu lub VNDK-SP), które są dostępne dla kodu dostawcy i z którymi można utworzyć link. Znajdziesz w nim też informacje o dodatkowych bibliotekach, które nie są związane z RenderScriptem, ale które zostały przekazane do kodu dostawcy.
Poniższa lista bibliotek może się różnić w zależności od wersji Androida, ale jest niezmienna w przypadku konkretnej wersji Androida. Aktualną listę dostępnych bibliotek znajdziesz na stronie /system/etc/ld.config.txt
.
RenderScript Libs | Biblioteki inne niż RenderScript |
---|---|
|
|
Konfiguracja przestrzeni nazw linkera
Ograniczenie łączenia, które uniemożliwia korzystanie z bibliotek nieznajdujących się w VNDK-SP przez kod dostawcy, jest egzekwowane w czasie wykonywania za pomocą przestrzeni nazw linkera. (szczegółowe informacje znajdziesz w prezentacji VNDK Design).
Na urządzeniu z Androidem 8.0 lub nowszym wszystkie interfejsy HAL w ramach tego samego procesu (SP-HAL) z wyjątkiem RenderScript są ładowane w przestrzeni nazw linkera sphal
. RenderScript jest ładowany do specyficznej dla niego przestrzeni nazw rs
, która umożliwia nieco luźniejszą kontrolę bibliotek RenderScript. Implementacja RS musi wczytywać skompilowany kod bitowy, dlatego do ścieżki przestrzeni nazw rs
jest dodawany ciąg /data/*/*.so
(inne identyfikatory SP-HAL nie mogą ładować libs z partycji danych).
Dodatkowo przestrzeń nazw rs
umożliwia stosowanie większej liczby bibliotek niż inne przestrzenie nazw. libmediandk.so
i libft2.so
są dostępne 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 awaryjnego korzystania z procesora
Podczas tworzenia kontekstu RS w zależności od obecności bitu RS_CONTEXT_LOW_LATENCY
wybierana jest ścieżka procesora lub karty graficznej. Gdy wybrana jest ścieżka CPU, libRS_internal.so
(główna implementacja
frameworku RS) jest bezpośrednio dlopen
z domyślnego przedrostka linkera, w którym dostępne są biblioteki RS dla danej platformy.
Implementacja RS HAL od dostawcy nie jest w ogóle używana, gdy wybrano ścieżkę awaryjnego korzystania z procesora. Tworzony jest obiekt RsContext
z wartością null mVendorDriverName
. libRSDriver.so
jest (domyślnie) dlopen
ed i sterownik lib jest wczytany z default
przestrzeni nazw, ponieważ wywołujący (libRS_internal.so
) jest też wczytywany w przestrzeni nazw default
.
Rysunek 3. Ścieżka awaryjna procesora.
Ścieżka GPU
W przypadku ścieżki GPU libRS_internal.so
jest wczytywana inaczej.
Najpierw usługa libRS.so
używa polecenia android.hardware.renderscript@1.0.so
(i bazowego libhidltransport.so
), aby wczytać android.hardware.renderscript@1.0-impl.so
(implementację dostawcy RS HAL) do innej przestrzeni nazw tagu łączącego o nazwie sphal
. RS
HAL następnie dlopen
s libRS_internal.so
w innej
przestrzeni nazw linkera o nazwie rs
.
Dostawcy mogą dostarczyć własnego sterownika 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
). Ta nazwa sterownika jest następnie dlopen
używana w kontekście RS w ścieżce GPU.
Tworzenie obiektu RsContext
jest delegowane do implementacji RS HAL. HAL wywołuje ponownie mechanizm RS za pomocą funkcji rsContextCreateVendor()
z nazwą sterownika do użycia jako argumentu. Następnie framework RS wczytuje określony sterownik podczas inicjowania interfejsu RsContext
. W tym przypadku biblioteka sterownika jest wczytywana 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 awaryjnego korzystania z GPU.
Podczas przechodzenia z przestrzeni nazw default
do przestrzeni nazw sphal
funkcja libhidltransport.so
używa funkcji android_load_sphal_library()
, aby wyraźnie zlecić linkerowi dynamicznemu 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 pliku /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 przestrzeni nazw /system/lib/vndk-sp
, w której znajduje się libRS_internal.so
). W tej konfiguracji wystarczy wywołanie funkcji dlopen()
w funkcji libRS_internal.so
, aby przejść do nowej przestrzeni nazw.
Ładowanie wtyczki UDW
bcc plugin
to biblioteka dostarczona przez dostawcę i wczytana do kompilatora bcc
. Ponieważ bcc
to proces systemowy w katalogu /system/bin
, biblioteka bcc plugin
może być uważana za SP-HAL (czyli interfejs HAL dostawcy, który można wczytać bezpośrednio do procesu systemowego bez korzystania z bindera). Jako SP-HAL w bibliotece bcc-plugin
:
- Nie można połączyć z bibliotekami działającymi tylko na platformie, takimi jak
libLLVM.so
. - Może zawierać linki tylko do bibliotek VNDK-SP dostępnych dla dostawcy.
To ograniczenie jest egzekwowane przez załadowanie bcc plugin
do przestrzeni nazw sphal
za pomocą funkcji android_sphal_load_library()
. We wcześniejszych 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 nowszych jest to określone w opcji -plugin
, a biblioteka jest ładowana bezpośrednio przez bcc
. Ta opcja umożliwia dostęp do projektu open source LLVM inny niż Android.
Rysunek 5. Ładowanie wtyczki bcc na Androidzie 7.x i starszych.
Rysunek 6. Ładowanie wtyczki bcc, Android 8.0 lub nowszy.
Ścieżki wyszukiwania dla pliku ld.mc
Podczas wykonywania ld.mc
niektóre biblioteki RS są przekazywane jako dane wejściowe do linkera. Kod bitowy RS z aplikacji jest połączony z bibliotekami środowiska wykonawczego, a gdy przekonwertowany kod bitowy jest wczytywany do procesu aplikacji, pakiety te są ponownie dynamicznie łączone z przekonwertowanego kodu bitowego.
Biblioteki środowiska wykonawczego obejmują:
libcompiler_rt.so
libm.so
libc.so
- Sterownik RS (
libRSDriver.so
lubOVERRIDE_RS_DRIVER
)
Podczas wczytywania skompilowanego kodu bitowego do procesu aplikacji podaj dokładnie tę samą bibliotekę, której używała ld.mc
. W przeciwnym razie skompilowany kod binarny może nie znaleźć symbolu, który był dostępny w momencie połączenia.
Aby to zrobić, framework RS używa różnych ścieżek wyszukiwania dla bibliotek runtime podczas wykonywania funkcji ld.mc
, w zależności od tego, czy framework RS jest wczytywany z poziomu /system/lib
czy /system/lib/vndk-sp
.
Można to określić, odczytując adres dowolnego symbolu biblioteki RS framework i używanie dladdr()
do mapowania ścieżki pliku do adresu.
Zasady SELinux
W Androidzie 8.0 i nowszych ze względu na zmiany w zasadach SELinux musisz przestrzegać określonych zasad (wykonywanych przez neverallows
) podczas etykietowania dodatkowych plików na partycji vendor
:
vendor_file
musi być domyślną etykietą dla wszystkich plików na partycjivendor
. Zasady platformy wymagają tego, aby uzyskać dostęp do implementacji interfejsu HAL typu passthrough.- Wszystkie nowe
exec_types
dodane w partycjivendor
za pomocą SEPolicy dostawcy muszą mieć atrybutvendor_file_type
. Jest to egzekwowane za pomocąneverallows
. - Aby uniknąć konfliktów z przyszłymi aktualizacjami platformy lub platformy, unikaj oznaczania na partycji
vendor
plików innych niżexec_types
. - Wszystkie zależności bibliotek dla identyfikatorów HAL identyfikowanych przez AOSP w ramach tego samego procesu muszą być oznaczone jako
same_process_hal_file
.
Szczegółowe informacje o zasadach SELinux znajdziesz w artykule SELinux w Androidzie.
Zgodność interfejsu ABI z kodem bitowym
Jeśli nie zostaną dodane żadne nowe interfejsy API, co oznacza brak aktualizacji wersji HAL, frameworki RS będą nadal używać dotychczasowego sterownika GPU (HAL 1.0).
W przypadku drobnych zmian w interfejsie HAL (HAL 1.1), które nie mają wpływu na kod bitowy, frameworki powinny stosować w przypadku nowo dodanych interfejsów API procesor CPU, a w pozostałych miejscach – sterownik GPU (HAL 1.0).
W przypadku istotnych zmian w interfejsie HAL (HAL 2.0), które mają wpływ na kompilację i linkowanie kodu bitowego, frameworki RS powinny zrezygnować z ładowania sterowników GPU dostarczonych przez dostawcę i zamiast tego używać procesora lub ścieżki Vulkan do przyspieszania.
Przetwarzanie kodu bitowego RenderScript odbywa się w 3 etapach:
Etap | Szczegóły |
---|---|
Kompilowanie |
|
Link |
|
Wczytaj |
|
Oprócz HAL interfejsami są też interfejsy API czasu wykonywania i wyeksportowane symbole. Od Androida 7.0 (API 24) nie zmienił się żaden z interfejsów. Poza tym na Androidzie 8.0 i nowszych nie planujemy wprowadzać żadnych zmian. Jeśli jednak interfejs się zmieni, wersja HAL również wzrośnie.
Implementacje dostawców
Aby sterownik GPU działał prawidłowo, w Androidzie 8.0 i nowszych wymagane są pewne zmiany.
Moduły sterujące
- Moduł sterownika nie może być zależny od żadnych bibliotek systemowych, które nie znajdują się na liście.
- Sterownik musi podać własną właściwość
android.hardware.renderscript@1.0-impl_{NAME}
lub zadeklarować 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:
- Wywołaj kompilator RenderScript konkretnego dostawcy w
/vendor/bin/
(preferowana metoda kompilacji na 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łanie systemu bcc:
/system/bin/bcc
z użyciem biblioteki dostarczonej 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, a zależność od libLLVM.so
nie może być łatwo usunięta, dostawca powinien skopiować bcc
(oraz wszystkie zależności inne niż LL-NDK, w tym libLLVM.so
i libbcc.so
) do partycji /vendor
.
Dostawcy muszą też wprowadzić te zmiany:
Rysunek 7. Zmiany sterownika dostawcy.
- Skopiuj
libclcore.bc
do partycji/vendor
. Dzięki temulibclcore.bc
,libLLVM.so
ilibbcc.so
są zsynchronizowane. - Zmień ścieżkę do pliku wykonywalnego
bcc
, ustawiając parametrRsdCpuScriptImpl::BCC_EXE_PATH
w implementacji RS HAL.
Zasada SELinux
Zasady SELinux wpływają zarówno na sterownik, jak i pliki wykonywalne kompilatora. Wszystkie moduły sterownika muszą mieć etykietę same_process_hal_file
w sekcji file_contexts
urządzenia. Na przykład:
/vendor/lib(64)?/libRSDriver_EXAMPLE\.so u:object_r:same_process_hal_file:s0
Proces aplikacji musi móc wywołać plik wykonywalny kompilatora oraz kopię pola UDW (/vendor/bin/bcc
) od dostawcy. Na przykład:
device/vendor_foo/device_bar/sepolicy/file_contexts: /vendor/bin/bcc u:object_r:same_process_hal_file:s0
Starsze urządzenia
Urządzenia starsze to te, które spełniają te warunki:
- PRODUCT_SHIPPING_API_LEVEL ma wartość mniejszą niż 26.
- Parametr PRODUCT_FULL_TREBLE_OVERRIDE nie jest zdefiniowany.
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]
. Ze względu na zmianę architektury związaną z OVERRIDE_RS_DRIVER
musisz jednak zainstalować aplikację android.hardware.renderscript@1.0-impl
na /vendor
partycji. Jeśli tego nie zrobisz, wymusza to przejście środowiska wykonawczego RenderScript na ścieżkę procesora.
Informacje o powodach wycofania technologii Renderscript znajdziesz na blogu dla deweloperów aplikacji na Androida: Android GPU Compute Going Forward (w języku angielskim). Informacje o wycofanych zasobach:
- Migracja z Renderscript
- Przykład migracji skryptu RenderScriptMigration
- Pakiet narzędzi Intrinsics Replacement Toolkit README
- Zastąpienie informacji o wartościach własnych pliku Toolkit.kt