Przestrzeń nazw linkera

Dynamiczny linker rozwiązuje 2 problemy w architekturze VNDK w Treble:

  • Biblioteki współdzielone SP-HAL i ich zależności, w tym biblioteki VNDK-SP, są ładowane do procesów platformy. Powinny istnieć mechanizmy zapobiegające konfliktom symboli.
  • dlopen()android_dlopen_ext() mogą wprowadzać zależności w czasie działania, które nie są widoczne w czasie kompilacji i które trudno wykryć za pomocą analizy statycznej.

Te 2 problemy można rozwiązać za pomocą mechanizmu przestrzeni nazw linkera. Ten mechanizm jest udostępniany przez dynamiczny linker. Może on izolować biblioteki współdzielone w różnych przestrzeniach nazw linkera, dzięki czemu biblioteki o tej samej nazwie, ale z różnymi symbolami nie będą ze sobą kolidować.

Z drugiej strony mechanizm przestrzeni nazw linkera zapewnia elastyczność, dzięki czemu niektóre biblioteki współdzielone mogą być eksportowane przez przestrzeń nazw linkera i używane przez inną przestrzeń nazw linkera. Wyeksportowane biblioteki współdzielone mogą stać się interfejsami programowania aplikacji, które są publiczne dla innych programów, a jednocześnie ukrywają szczegóły implementacji w przestrzeniach nazw linkera.

Na przykład /system/lib[64]/libcutils.so/system/lib[64]/vndk-sp-${VER}/libcutils.so to 2 biblioteki udostępnione. Te 2 biblioteki mogą mieć różne symbole. Są one wczytywane do różnych przestrzeni nazw linkera, dzięki czemu moduły platformy mogą zależeć od /system/lib[64]/libcutils.so, a biblioteki współdzielone SP-HAL mogą zależeć od /system/lib[64]/vndk-sp-${VER}/libcutils.so.

Z kolei /system/lib[64]/libc.so to przykład biblioteki publicznej, która jest eksportowana przez przestrzeń nazw linkera i importowana do wielu przestrzeni nazw linkera. Zależności /system/lib[64]/libc.so, takie jak libnetd_client.so, są wczytywane do przestrzeni nazw, w której znajduje się /system/lib[64]/libc.so. Inne przestrzenie nazw nie będą miały dostępu do tych zależności. Ten mechanizm zawiera szczegóły implementacji, a jednocześnie udostępnia interfejsy publiczne.

Jak to działa

Dynamiczny linker odpowiada za wczytywanie bibliotek współdzielonych określonych we wpisach DT_NEEDED lub bibliotek współdzielonych określonych przez argument dlopen() lub android_dlopen_ext(). W obu przypadkach dynamiczny linker znajduje przestrzeń nazw linkera, w której znajduje się wywołujący, i próbuje załadować zależności do tej samej przestrzeni nazw linkera. Jeśli dynamiczny linker nie może wczytać biblioteki współdzielonej do określonej przestrzeni nazw linkera, prosi połączoną przestrzeń nazw linkera o wyeksportowane biblioteki współdzielone.

Format pliku konfiguracji

Format pliku konfiguracyjnego jest oparty na formacie pliku INI. Typowy plik konfiguracji wygląda tak:

dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

[system]
additional.namespaces = sphal,vndk

namespace.default.isolated = true
namespace.default.search.paths = /system/${LIB}
namespace.default.permitted.paths = /system/${LIB}/hw
namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw

namespace.sphal.isolated = true
namespace.sphal.visible = true
namespace.sphal.search.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.permitted.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.asan.permitted.paths  = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.links = default,vndk
namespace.sphal.link.default.shared_libs = libc.so:libm.so
namespace.sphal.link.vndk.shared_libs = libbase.so:libcutils.so

namespace.vndk.isolated = true
namespace.vndk.search.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.permitted.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = libc.so:libm.so

[vendor]
namespace.default.isolated = false
namespace.default.search.paths = /vendor/${LIB}:/system/${LIB}

Plik konfiguracji zawiera:

  • Na początku kilka właściwości mapowania sekcji katalogu, aby dynamiczny linker mógł wybrać odpowiednią sekcję.
  • Kilka sekcji konfiguracji przestrzeni nazw linkera:
    • Każda sekcja zawiera kilka przestrzeni nazw (wierzchołków wykresu) i kilka linków rezerwowych między przestrzeniami nazw (łuków wykresu).
    • Każda przestrzeń nazw ma własne ustawienia izolacji, ścieżek wyszukiwania, dozwolonych ścieżek i widoczności.

Tabele poniżej zawierają szczegółowe opisy poszczególnych właściwości.

Właściwość mapowania sekcji katalogu

Właściwość Opis Przykład

dir.name

Ścieżka do katalogu, do którego odnosi się sekcja [name].

Każda właściwość mapuje pliki wykonywalne w katalogu na sekcję konfiguracji przestrzeni nazw linkera. Mogą istnieć 2 (lub więcej) usług, które mają ten sam atrybut name, ale wskazują różne katalogi.

dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

Oznacza to, że konfiguracja określona w sekcji [system] dotyczy plików wykonywalnych wczytywanych z /system/bin lub /system/xbin.

Konfiguracja określona w sekcji [vendor] dotyczy plików wykonywalnych wczytywanych z /vendor/bin.

Właściwości relacji

Właściwość Opis Przykład
additional.namespaces

Lista dodatkowych przestrzeni nazw (oprócz przestrzeni nazw default) dla sekcji rozdzielona przecinkami.

additional.namespaces = sphal,vndk

Oznacza to, że w konfiguracji [system] znajdują się 3 przestrzenie nazw (default, sphal i vndk).

namespace.name.links

Lista przestrzeni nazw rezerwowych rozdzielona przecinkami.

Jeśli biblioteki udostępnionej nie można znaleźć w bieżącej przestrzeni nazw, dynamiczny linker próbuje wczytać ją z przestrzeni nazw rezerwowych. Przestrzeń nazw podana na początku listy ma wyższy priorytet.

namespace.sphal.links = default,vndk

Jeśli biblioteka współużytkowana lub plik wykonywalny zażąda biblioteki współużytkowanej, której nie można załadować do przestrzeni nazw sphal, dynamiczny linker spróbuje załadować bibliotekę współużytkowaną z przestrzeni nazw default.

Jeśli nie można załadować biblioteki udostępnionej z przestrzeni nazw default, dynamiczny linker próbuje załadować ją z przestrzeni nazw vndk.

Jeśli wszystkie próby zawiodą, dynamiczny linker zwróci błąd.

namespace.name.link.other.shared_libs

Lista zasobów wspólnych rozdzielonych dwukropkiem, które można przeszukiwać w przestrzeniach nazw other, gdy nie można ich znaleźć w przestrzeni nazw other.name

Tej właściwości nie można używać z wartością namespace.name.link.other.allow_all_shared_libs.

namespace.sphal.link.default.shared_libs = libc.so:libm.so

Oznacza to, że link rezerwowy akceptuje tylko libc.so lub libm.so jako nazwę żądanej biblioteki. Dynamiczny linker ignoruje link rezerwowy z przestrzeni nazw sphal do default, jeśli żądana nazwa biblioteki nie jest libc.so ani libm.so.

namespace.name.link.other.allow_all_shared_libs

Wartość logiczna wskazująca, czy można przeszukiwać wszystkie zasoby wspólne w przestrzeni nazw other, gdy nie można ich znaleźć w przestrzeni nazw name.

Tej właściwości nie można używać z wartością namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

Oznacza to, że wszystkie nazwy bibliotek mogą przechodzić przez link rezerwowy z przestrzeni nazw vndk do sphal.

Właściwości przestrzeni nazw

Właściwość Opis Przykład
namespace.name.isolated

Wartość logiczna wskazująca, czy dynamiczny linker powinien sprawdzać, gdzie znajduje się biblioteka współdzielona.

Jeśli isolated ma wartość true, można wczytać tylko biblioteki udostępnione, które znajdują się w jednym z katalogów search.paths (z wyłączeniem podkatalogów) lub pod jednym z katalogów permitted.paths (z uwzględnieniem podkatalogów).

Jeśli isolated ma wartość false (domyślną), dynamiczny linker nie sprawdza ścieżki bibliotek współużytkowanych.

namespace.sphal.isolated = true

Oznacza to, że do przestrzeni nazw sphal można wczytywać tylko biblioteki udostępnione w search.paths lub w permitted.paths.

namespace.name.search.paths

Lista katalogów rozdzielonych dwukropkiem, w których mają być wyszukiwane biblioteki udostępnione.

Katalogi określone w search.paths są dodawane na początku nazwy żądanej biblioteki, jeśli wywołania funkcji w przypadku wpisów dlopen() lub DT_NEEDED nie określają pełnej ścieżki. Katalog określony na początku listy ma wyższy priorytet.

Gdy wartość isolated to true, biblioteki współdzielone, które znajdują się w jednym z katalogów search.paths (z wyłączeniem podkatalogów), można wczytać niezależnie od właściwości permitted.paths.

Jeśli na przykład wartość search.paths to /system/${LIB}, a wartość permitted.paths jest pusta, można wczytać wartość /system/${LIB}/libc.so, ale nie można wczytać wartości /system/${LIB}/vndk/libutils.so.

namespace.default.search.paths = /system/${LIB}

Oznacza to, że dynamiczny linker wyszukuje biblioteki współdzielone w /system/${LIB}.

namespace.name.asan.search.paths

Lista katalogów oddzielonych dwukropkiem, w których należy szukać bibliotek współdzielonych, gdy włączona jest funkcja AddressSanitizer (ASan).

Gdy włączona jest funkcja ASan, zasada namespace.name.search.paths jest ignorowana.

namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}

Oznacza to, że gdy ASan jest włączony, dynamiczny linker najpierw wyszukuje /data/asan/system/${LIB}, a potem /system/${LIB}.

namespace.name.permitted.paths

Lista katalogów (wraz z podkatalogami) oddzielonych dwukropkiem, z których dynamiczny linker może wczytywać biblioteki współdzielone (oprócz search.paths), gdy isolated ma wartość true.

Można też załadować biblioteki udostępnione znajdujące się w podkatalogach permitted.paths. Jeśli na przykład wartość permitted.paths to /system/${LIB}, można wczytać zarówno /system/${LIB}/libc.so, jak i /system/${LIB}/vndk/libutils.so.

Jeśli isolated to false, wartości permitted.paths są ignorowane i wyświetlane jest ostrzeżenie.

namespace.default.permitted.paths = /system/${LIB}/hw

Oznacza to, że biblioteki udostępnione w obszarze /system/${LIB}/hw można wczytać do odizolowanej przestrzeni nazw default.

Na przykład bez permitted.paths nie można wczytać libaudiohal.so do przestrzeni nazw /system/${LIB}/hw/audio.a2dp.default.so.default

namespace.name.asan.permitted.paths

Lista katalogów oddzielonych dwukropkiem, z których dynamiczny linker może ładować biblioteki współdzielone, gdy włączona jest funkcja ASan.

Gdy włączona jest funkcja ASan, zasada namespace.name.permitted.paths jest ignorowana.

namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw

Oznacza to, że gdy ASan jest włączony, biblioteki współdzielone w /data/asan/system/${LIB}/hw lub /system/${LIB}/hw można wczytywać do odizolowanej przestrzeni nazw default.

namespace.name.visible

Wartość logiczna wskazująca, czy program (inny niż libc) może uzyskać uchwyt przestrzeni nazw linkera za pomocą funkcji android_get_exported_namespace() i otworzyć bibliotekę współdzieloną w przestrzeni nazw linkera, przekazując uchwyt do funkcji android_dlopen_ext().

Jeśli visible ma wartość true, android_get_exported_namespace() zawsze zwraca uchwyt, jeśli przestrzeń nazw istnieje.

Jeśli visible ma wartość false (domyślną), android_get_exported_namespace() zawsze zwraca NULL niezależnie od obecności przestrzeni nazw. Biblioteki współdzielone można wczytywać do tej przestrzeni nazw tylko wtedy, gdy (1) są wymagane przez inną przestrzeń nazw linkera, która ma link rezerwowy do tej przestrzeni nazw, lub (2) są wymagane przez inne biblioteki współdzielone lub pliki wykonywalne w tej przestrzeni nazw.

namespace.sphal.visible = true

Oznacza to, że funkcja android_get_exported_namespace("sphal") może zwrócić prawidłowy uchwyt przestrzeni nazw linkera.

Tworzenie przestrzeni nazw linkera

W Androidzie 11 konfiguracja linkera jest tworzona w czasie działania w katalogu /linkerconfig zamiast przy użyciu zwykłych plików tekstowych w katalogu ${android-src}/system/core/rootdir/etc. Konfiguracja jest generowana podczas uruchamiania na podstawie środowiska wykonawczego, które obejmuje te elementy:

  • Jeśli urządzenie obsługuje VNDK
  • Docelowa wersja VNDK partycji dostawcy
  • Wersja VNDK podziału produktu
  • Zainstalowane moduły APEX

Konfiguracja linkera jest tworzona przez rozwiązywanie zależności między przestrzeniami nazw linkera. Jeśli na przykład w modułach APEX są dostępne aktualizacje, które obejmują aktualizacje zależności, generowana jest konfiguracja linkera odzwierciedlająca te zmiany. Więcej informacji o tworzeniu konfiguracji linkera znajdziesz w ${android-src}/system/linkerconfig.

Izolacja przestrzeni nazw linkera

Dostępne są 3 typy konfiguracji. W zależności od wartości PRODUCT_TREBLE_LINKER_NAMESPACESBOARD_VNDK_VERSIONBoardConfig.mk odpowiednia konfiguracja jest generowana podczas uruchamiania.

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
Wybrana konfiguracja Wymagania dotyczące VTS
true current VNDK Obowiązkowe w przypadku urządzeń wprowadzonych na rynek z Androidem 9 lub nowszym
Puste VNDK Lite Obowiązkowe w przypadku urządzeń wprowadzonych na rynek z Androidem 8.x
false Puste Legacy W przypadku urządzeń innych niż Treble

Konfiguracja VNDK Lite izoluje biblioteki współdzielone SP-HAL i VNDK-SP. W Androidzie 8.0 musi to być plik konfiguracji dynamicznego linkera, gdy PRODUCT_TREBLE_LINKER_NAMESPACES ma wartość true.

Konfiguracja VNDK izoluje też biblioteki współdzielone SP-HAL i VNDK-SP. Dodatkowo ta konfiguracja zapewnia pełną izolację dynamicznego linkera. Dzięki temu moduły w partycji systemowej nie będą zależeć od bibliotek współdzielonych w partycjach dostawcy i na odwrót.

W Androidzie 8.1 lub nowszym konfiguracja VNDK jest domyślna. Zdecydowanie zalecamy włączenie pełnej izolacji dynamicznego linkera przez ustawienie BOARD_VNDK_VERSION na current.

Konfiguracja VNDK

Konfiguracja VNDK izoluje zależności biblioteki udostępnionej między partycją systemową a partycjami dostawcy. W porównaniu z konfiguracjami wymienionymi w poprzedniej sekcji różnice są następujące:

  • Procesy platformy

    • Zostaną utworzone przestrzenie nazw default, vndk, sphal i rs.
    • Wszystkie przestrzenie nazw są odizolowane.
    • Systemowe biblioteki udostępnione są wczytywane do przestrzeni nazw default.
    • SP-HAL są wczytywane do przestrzeni nazw sphal.
    • Biblioteki współdzielone VNDK-SP załadowane do przestrzeni nazw vndk.
  • Procesy dostawcy

    • Tworzone są przestrzenie nazw default, vndk i system.
    • Przestrzeń nazw default jest odizolowana.
    • Biblioteki udostępnione dostawcy są wczytywane do przestrzeni nazw default.
    • Biblioteki współdzielone VNDK i VNDK-SP są wczytywane do przestrzeni nazw vndk.
    • LL-NDK i jego zależności są ładowane do przestrzeni nazw system.

Zależności między przestrzeniami nazw linkera zostały zilustrowane poniżej.

Graf przestrzeni nazw linkera opisany w konfiguracji VNDK

Rysunek 1. Izolacja przestrzeni nazw linkera (konfiguracja VNDK).

Na powyższym obrazie LL-NDKVNDK-SP oznaczają te biblioteki współdzielone:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libGLESv3.so
    • libandroid_net.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libneuralnetworks.so
    • libsync.so
    • libvndksupport.so
    • libvulkan.so
  • VNDK-SP
    • android.hardware.graphics.common@1.0.so
    • android.hardware.graphics.mapper@2.0.so
    • android.hardware.renderscript@1.0.so
    • android.hidl.memory@1.0.so
    • libRSCpuRef.so
    • libRSDriver.so
    • libRS_internal.so
    • libbase.so
    • libbcinfo.so
    • libc++.so
    • libcutils.so
    • libhardware.so
    • libhidlbase.so
    • libhidlmemory.so
    • libhidltransport.so
    • libhwbinder.so
    • libion.so
    • libutils.so
    • libz.so

Więcej informacji znajdziesz w /linkerconfig/ld.config.txt na urządzeniu.

Konfiguracja VNDK Lite

Od Androida 8.0 dynamiczny linker jest skonfigurowany tak, aby izolować biblioteki współdzielone SP-HAL i VNDK-SP, dzięki czemu ich symbole nie powodują konfliktów z innymi bibliotekami współdzielonymi platformy. Relacja między przestrzeniami nazw linkera jest pokazana poniżej.

Graf przestrzeni nazw linkera opisany w konfiguracji VNDK Lite
Rysunek 2. Izolacja przestrzeni nazw linkera (konfiguracja VNDK Lite)

LL-NDKVNDK-SP to nazwy tych bibliotek udostępnionych:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libstdc++.so (nie ma w konfiguracji)
    • libsync.so
    • libvndksupport.so
    • libz.so (przeniesiono do VNDK-SP w konfiguracji)
  • VNDK-SP
    • android.hardware.graphics.common@1.0.so
    • android.hardware.graphics.mapper@2.0.so
    • android.hardware.renderscript@1.0.so
    • android.hidl.memory@1.0.so
    • libbase.so
    • libc++.so
    • libcutils.so
    • libhardware.so
    • libhidlbase.so
    • libhidlmemory.so
    • libhidltransport.so
    • libhwbinder.so
    • libion.so
    • libutils.so

Tabela poniżej zawiera konfigurację przestrzeni nazw dla procesów frameworka, która jest wyciągiem z sekcji [system] w konfiguracji VNDK Lite.

Przestrzeń nazw Właściwość Wartość
default search.paths /system/${LIB}
/odm/${LIB}
/vendor/${LIB}
/product/${LIB}
isolated false
sphal search.paths /odm/${LIB}
/vendor/${LIB}
permitted.paths /odm/${LIB}
/vendor/${LIB}
isolated true
visible true
links default,vndk,rs
link.default.shared_libs LL-NDK
link.vndk.shared_libs VNDK-SP
link.rs.shared_libs libRS_internal.so
vndk (w przypadku VNDK-SP) search.paths /odm/${LIB}/vndk-sp
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-sp-${VER}
permitted.paths /odm/${LIB}/hw
/odm/${LIB}/egl
/vendor/${LIB}/hw
/vendor/${LIB}/egl
/system/${LIB}/vndk-sp-${VER}/hw
isolated true
visible true
links default
link.default.shared_libs LL-NDK
rs (w przypadku RenderScript) search.paths /odm/${LIB}/vndk-sp
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-sp-${VER}
/odm/${LIB}
/vendor/${LIB}
permitted.paths /odm/${LIB}
/vendor/${LIB}
/data (w przypadku skompilowanego jądra RS)
isolated true
visible true
links default,vndk
link.default.shared_libs LL-NDK
libmediandk.so
libft2.so
link.vndk.shared_libs VNDK-SP

Tabela poniżej przedstawia konfigurację przestrzeni nazw dla procesów dostawcy, która została wyodrębniona z sekcji [vendor] w konfiguracji VNDK Lite.

Przestrzeń nazw Właściwość Wartość
default search.paths /odm/${LIB}
/odm/${LIB}/vndk
/odm/${LIB}/vndk-sp
/vendor/${LIB}
/vendor/${LIB}/vndk
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-${VER}
/system/${LIB}/vndk-sp-${VER}
/system/${LIB} (wycofano)
/product/${LIB} (wycofano)
isolated false

Więcej informacji znajdziesz w /linkerconfig/ld.config.txt na urządzeniu.

Historia dokumentu

Zmiany w Androidzie 11

  • W Androidzie 11 statyczne pliki ld.config.*.txt zostały usunięte z bazy kodu, a zamiast nich LinkerConfig generuje je w czasie działania.

Zmiany w Androidzie 9

  • W Androidzie 9 do procesów dostawcy dodano przestrzeń nazw linkera vndk, a biblioteki współdzielone VNDK są odizolowane od domyślnej przestrzeni nazw linkera.
  • Zastąp PRODUCT_FULL_TREBLE bardziej szczegółowym tekstem PRODUCT_TREBLE_LINKER_NAMESPACES.
  • Android 9 zmienia nazwy tych plików konfiguracyjnych dynamicznego linkera:
    Android 8.x Android 9 Opis
    ld.config.txt.in ld.config.txt W przypadku urządzeń z izolacją przestrzeni nazw linkera w czasie działania
    ld.config.txt ld.config.vndk_lite.txt W przypadku urządzeń z izolacją przestrzeni nazw linkera VNDK-SP
    ld.config.legacy.txt ld.config.legacy.txt Starsze urządzenia z Androidem 7.x lub starszym
  • Usuń android.hardware.graphics.allocator@2.0.so.
  • Dodano partycje productodm.