Spazio dei nomi del linker

Il linker dinamico affronta due sfide nella progettazione di Treble VNDK:

  • Le librerie condivise SP-HAL e le relative dipendenze, incluse le librerie VNDK-SP, vengono caricate nei processi del framework. Dovrebbero esserci alcuni meccanismi per evitare conflitti di simboli.
  • dlopen() e android_dlopen_ext() possono introdurre alcune dipendenze di runtime che non sono visibili al momento della compilazione e possono essere difficili da rilevare utilizzando l'analisi statica.

Queste due sfide possono essere risolte dal meccanismo dello spazio dei nomi del linker. Questo meccanismo è fornito dal linker dinamico. Può isolare le librerie condivise in spazi dei nomi del linker diversi in modo che le librerie con lo stesso nome ma con simboli diversi non entrino in conflitto.

D'altra parte, il meccanismo dello spazio dei nomi del linker offre la flessibilità in modo che alcune librerie condivise possano essere esportate da uno spazio dei nomi del linker e utilizzate da un altro spazio dei nomi del linker. Queste librerie condivise esportate possono diventare interfacce di programmazione delle applicazioni pubbliche per altri programmi, nascondendo i dettagli di implementazione all'interno dei propri spazi dei nomi del linker.

Ad esempio, /system/lib[64]/libcutils.so e /system/lib[64]/vndk-sp-${VER}/libcutils.so sono due librerie condivise. Queste due librerie possono avere simboli diversi. Vengono caricati in spazi dei nomi del linker diversi, in modo che i moduli del framework possano dipendere da /system/lib[64]/libcutils.so e le librerie condivise SP-HAL possano dipendere da /system/lib[64]/vndk-sp-${VER}/libcutils.so.

D'altra parte, /system/lib[64]/libc.so è un esempio di una libreria pubblica esportata da uno spazio dei nomi del linker e importata in molti spazi dei nomi del linker. Le dipendenze di /system/lib[64]/libc.so, ad esempio libnetd_client.so, vengono caricate nello spazio dei nomi in cui si trova /system/lib[64]/libc.so. Gli altri spazi dei nomi non avranno accesso a queste dipendenze. Questo meccanismo incapsula i dettagli di implementazione fornendo le interfacce pubbliche.

Come funziona?

Il linker dinamico è responsabile del caricamento delle librerie condivise specificate nelle voci DT_NEEDED o delle librerie condivise specificate dall'argomento di dlopen() o android_dlopen_ext(). In entrambi i casi, il linker dinamico trova lo spazio dei nomi del linker in cui risiede il chiamante e tenta di caricare le dipendenze nello stesso spazio dei nomi del linker. Se il linker dinamico non riesce a caricare la libreria condivisa nello spazio dei nomi del linker specificato, chiede allo spazio dei nomi del linker collegato le librerie condivise esportate.

Formato del file di configurazione

Il formato del file di configurazione si basa sul formato del file INI. Un tipico file di configurazione ha il seguente aspetto:

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}

Il file di configurazione include:

  • Diverse proprietà di mappatura delle sezioni della directory all'inizio per consentire al linker dinamico di selezionare la sezione effettiva.
  • Diverse sezioni di configurazione degli spazi dei nomi del linker:
    • Ogni sezione contiene diversi spazi dei nomi (vertici del grafico) e diversi link di fallback tra gli spazi dei nomi (archi del grafico).
    • Ogni spazio dei nomi ha le proprie impostazioni di isolamento, percorsi di ricerca, percorsi consentiti e visibilità.

Le tabelle seguenti descrivono in dettaglio il significato di ogni proprietà.

Proprietà di mappatura della sezione della directory

Proprietà Descrizione Esempio

dir.name

Un percorso a una directory a cui si applica la sezione [name].

Ogni proprietà mappa gli eseguibili nella directory a una sezione di configurazione degli spazi dei nomi del linker. Potrebbero esserci due (o più) proprietà con lo stesso name, ma che puntano a directory diverse.

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

Ciò indica che la configurazione specificata nella sezione [system] si applica agli eseguibili caricati da /system/bin o /system/xbin.

La configurazione specificata nella sezione [vendor] si applica agli eseguibili caricati da /vendor/bin.

Proprietà della relazione

Proprietà Descrizione Esempio
additional.namespaces

Un elenco separato da virgole di spazi dei nomi aggiuntivi (oltre allo spazio dei nomi default) per la sezione.

additional.namespaces = sphal,vndk

Ciò indica che nella configurazione [system] sono presenti tre spazi dei nomi (default, sphal e vndk).

namespace.name.links

Un elenco di spazi dei nomi di riserva separati da virgole.

Se una libreria condivisa non viene trovata nello spazio dei nomi corrente, il linker dinamico tenta di caricare la libreria condivisa dagli spazi dei nomi di riserva. Lo spazio dei nomi specificato all'inizio dell'elenco ha una priorità maggiore.

namespace.sphal.links = default,vndk

Se una libreria condivisa o un eseguibile richiede una libreria condivisa che non può essere caricata nello spazio dei nomi sphal, il linker dinamico tenta di caricare la libreria condivisa dallo spazio dei nomi default.

Se la libreria condivisa non può essere caricata nemmeno dallo spazio dei nomi default, il linker dinamico tenta di caricare la libreria condivisa dallo spazio dei nomi vndk.

Infine, se tutti i tentativi falliscono, il linker dinamico restituisce un errore.

namespace.name.link.other.shared_libs

Un elenco separato da due punti di librerie condivise in cui è possibile eseguire ricerche negli spazi dei nomi other quando queste librerie non sono disponibili nello spazio dei nomi name.

Questa proprietà non può essere utilizzata con namespace.name.link.other.allow_all_shared_libs.

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

Ciò indica che il link di riserva accetta solo libc.so o libm.so come nome della libreria richiesta. Il linker dinamico ignora il link di riserva dallo spazio dei nomi sphal a default se il nome della libreria richiesta non è libc.so o libm.so.

namespace.name.link.other.allow_all_shared_libs

Un valore booleano che indica se è possibile eseguire ricerche in tutte le librerie condivise nello spazio dei nomi other quando non è possibile trovarle nello spazio dei nomi name.

Questa proprietà non può essere utilizzata con namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

Ciò indica che tutti i nomi delle librerie possono passare attraverso il link di fallback dallo spazio dei nomi vndk allo spazio dei nomi sphal.

Proprietà dello spazio dei nomi

Proprietà Descrizione Esempio
namespace.name.isolated

Un valore booleano che indica se il linker dinamico deve controllare dove si trova la libreria condivisa.

Se isolated è true, possono essere caricate solo le librerie condivise che si trovano in una delle directory search.paths (escluse le sottodirectory) o che si trovano sotto una delle directory permitted.paths (incluse le sottodirectory).

Se isolated è false (impostazione predefinita), il linker dinamico non controlla il percorso delle librerie condivise.

namespace.sphal.isolated = true

Ciò indica che solo le librerie condivise in search.paths o in permitted.paths possono essere caricate nello spazio dei nomi sphal.

namespace.name.search.paths

Un elenco di directory separate da due punti in cui cercare le librerie condivise.

Le directory specificate in search.paths vengono anteposte al nome della libreria richiesta se le chiamate di funzione alle voci dlopen() o DT_NEEDED non specificano il percorso completo. La directory specificata all'inizio dell'elenco ha una priorità maggiore.

Quando isolated è true, le librerie condivise che si trovano in una delle directory search.paths (escluse le sottodirectory) possono essere caricate indipendentemente dalla proprietà permitted.paths.

Ad esempio, se search.paths è /system/${LIB} e permitted.paths è vuoto, /system/${LIB}/libc.so può essere caricato, ma /system/${LIB}/vndk/libutils.so non può essere caricato.

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

Ciò indica che il linker dinamico cerca /system/${LIB} per le librerie condivise.

namespace.name.asan.search.paths

Un elenco di directory separate da due punti in cui cercare le librerie condivise quando AddressSanitizer (ASan) è abilitato.

namespace.name.search.paths viene ignorato quando ASan è abilitato.

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

Ciò indica che quando ASan è abilitato, il linker dinamico esegue prima la ricerca in /data/asan/system/${LIB} e poi in /system/${LIB}.

namespace.name.permitted.paths

Un elenco di directory (incluse le sottodirectory) separate da due punti in cui il linker dinamico può caricare le librerie condivise (oltre a search.paths) quando isolated è true.

Possono essere caricate anche le librerie condivise che si trovano nelle sottodirectory di permitted.paths. Ad esempio, se permitted.paths è /system/${LIB}, possono essere caricati sia /system/${LIB}/libc.so che /system/${LIB}/vndk/libutils.so.

Se isolated è false, permitted.paths vengono ignorati e viene emesso un avviso.

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

Ciò indica che le librerie condivise in /system/${LIB}/hw possono essere caricate nello spazio dei nomi default isolato.

Ad esempio, senza permitted.paths, libaudiohal.so non può caricare /system/${LIB}/hw/audio.a2dp.default.so nello spazio dei nomi default.

namespace.name.asan.permitted.paths

Un elenco di directory separate da due punti in cui il linker dinamico può caricare le librerie condivise quando ASan è attivato.

namespace.name.permitted.paths viene ignorato quando ASan è abilitato.

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

Ciò indica che quando ASan è abilitato, le librerie condivise in /data/asan/system/${LIB}/hw o /system/${LIB}/hw possono essere caricate nello spazio dei nomi default isolato.

namespace.name.visible

Un valore booleano che indica se il programma (diverso da libc) può ottenere un handle dello spazio dei nomi del linker con android_get_exported_namespace() e aprire una libreria condivisa nello spazio dei nomi del linker passando l'handle a android_dlopen_ext().

Se visible è true, android_get_exported_namespace() restituisce sempre l'handle se lo spazio dei nomi esiste.

Se visible è false (impostazione predefinita), android_get_exported_namespace() restituisce sempre NULL indipendentemente dalla presenza dello spazio dei nomi. Le librerie condivise possono essere caricate in questo spazio dei nomi solo se (1) sono richieste da un altro spazio dei nomi del linker che ha un link di riserva a questo spazio dei nomi oppure (2) sono richieste da altre librerie condivise o eseguibili in questo spazio dei nomi.

namespace.sphal.visible = true

Ciò indica che android_get_exported_namespace("sphal") può restituire un handle dello spazio dei nomi del linker valido.

Creazione dello spazio dei nomi del linker

In Android 11, la configurazione del linker viene creata in fase di runtime in /linkerconfig anziché utilizzare file di testo normale in ${android-src}/system/core/rootdir/etc. La configurazione viene generata all'avvio in base all'ambiente di runtime, che include i seguenti elementi:

  • Se il dispositivo supporta VNDK
  • Versione VNDK di destinazione della partizione del fornitore
  • Versione VNDK della partizione prodotto
  • Moduli APEX installati

La configurazione del linker viene creata risolvendo le dipendenze tra gli spazi dei nomi del linker. Ad esempio, se sono presenti aggiornamenti sui moduli APEX che includono aggiornamenti delle dipendenze, la configurazione del linker viene generata in modo da riflettere queste modifiche. Per ulteriori dettagli sulla creazione della configurazione del linker, consulta ${android-src}/system/linkerconfig.

Isolamento dello spazio dei nomi del linker

Esistono tre tipi di configurazione. A seconda del valore di PRODUCT_TREBLE_LINKER_NAMESPACES e BOARD_VNDK_VERSION in BoardConfig.mk, la configurazione corrispondente viene generata all'avvio.

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
Configurazione selezionata Requisito VTS
true current VNDK Obbligatorio per i dispositivi lanciati con Android 9 o versioni successive
Vuoto VNDK Lite Obbligatorio per i dispositivi lanciati con Android 8.x
false Vuoto Legacy Per i dispositivi non Treble

La configurazione di VNDK Lite isola le librerie condivise SP-HAL e VNDK-SP. In Android 8.0, questo deve essere il file di configurazione per il linker dinamico quando PRODUCT_TREBLE_LINKER_NAMESPACES è true.

La configurazione di VNDK isola anche le librerie condivise SP-HAL e VNDK-SP. Inoltre, questa configurazione fornisce l'isolamento completo del linker dinamico. Ciò garantisce che i moduli nella partizione di sistema non dipendano dalle librerie condivise nelle partizioni del fornitore e viceversa.

In Android 8.1 o versioni successive, la configurazione VNDK è quella predefinita ed è consigliabile attivare l'isolamento completo del linker dinamico impostando BOARD_VNDK_VERSION su current.

Configurazione VNDK

La configurazione VNDK isola le dipendenze della libreria condivisa tra la partizione di sistema e le partizioni del fornitore. Rispetto alle configurazioni menzionate nella sottosezione precedente, le differenze sono riassunte come segue:

  • Processi del framework

    • Vengono creati gli spazi dei nomi default, vndk, sphal e rs.
    • Tutti gli spazi dei nomi sono isolati.
    • Le librerie condivise di sistema vengono caricate nello spazio dei nomi default.
    • Gli SP-HAL vengono caricati nello spazio dei nomi sphal.
    • Librerie condivise VNDK-SP caricate nello spazio dei nomi vndk.
  • Procedure del fornitore

    • Vengono creati gli spazi dei nomi default, vndk e system.
    • Lo spazio dei nomi default è isolato.
    • Le librerie condivise dei fornitori vengono caricate nello spazio dei nomi default.
    • Le librerie condivise VNDK e VNDK-SP vengono caricate nello spazio dei nomi vndk.
    • LL-NDK e le relative dipendenze vengono caricati nello spazio dei nomi system.

La relazione tra gli spazi dei nomi del linker è illustrata di seguito.

Grafico dello spazio dei nomi del linker descritto nella configurazione VNDK
Figura 1. Isolamento dello spazio dei nomi del linker (configurazione VNDK)

Nell'immagine sopra, LL-NDK e VNDK-SP indicano le seguenti librerie condivise:

  • 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

Puoi trovare maggiori dettagli in /linkerconfig/ld.config.txt del dispositivo.

Configurazione di VNDK Lite

A partire da Android 8.0, il linker dinamico è configurato per isolare le librerie condivise SP-HAL e VNDK-SP in modo che i relativi simboli non entrino in conflitto con altre librerie condivise del framework. La relazione tra gli spazi dei nomi del linker è mostrata di seguito.

Grafico dello spazio dei nomi del linker descritto nella configurazione di VNDK Lite
Figura 2. Isolamento dello spazio dei nomi del linker (configurazione VNDK Lite)

LL-NDK e VNDK-SP sono acronimi delle seguenti librerie condivise:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libstdc++.so (non nella configurazione)
    • libsync.so
    • libvndksupport.so
    • libz.so (spostato in VNDK-SP nella configurazione)
  • 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

La tabella seguente elenca la configurazione degli spazi dei nomi per i processi del framework, che è estratta dalla sezione [system] della configurazione VNDK Lite.

Namespace Proprietà Valore
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 (per 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 (per 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 (per il kernel RS compilato)
isolated true
visible true
links default,vndk
link.default.shared_libs LL-NDK
libmediandk.so
libft2.so
link.vndk.shared_libs VNDK-SP

La tabella seguente mostra la configurazione degli spazi dei nomi per i processi del fornitore, estratta dalla sezione [vendor] della configurazione VNDK Lite.

Namespace Proprietà Valore
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} (deprecato)
/product/${LIB} (deprecato)
isolated false

Per ulteriori dettagli, consulta /linkerconfig/ld.config.txt dal dispositivo.

Cronologia documento

Modifiche di Android 11

  • In Android 11, i file statici ld.config.*.txt vengono rimossi dal codebase e LinkerConfig li genera in fase di runtime.

Modifiche di Android 9

  • In Android 9, lo spazio dei nomi del linker vndk viene aggiunto ai processi del fornitore e le librerie condivise VNDK vengono isolate dallo spazio dei nomi del linker predefinito.
  • Sostituisci PRODUCT_FULL_TREBLE con un valore più specifico PRODUCT_TREBLE_LINKER_NAMESPACES.
  • Android 9 modifica i nomi dei seguenti file di configurazione del linker dinamico.
    Android 8.x Android 9 Descrizione
    ld.config.txt.in ld.config.txt Per i dispositivi con isolamento dello spazio dei nomi del linker di runtime
    ld.config.txt ld.config.vndk_lite.txt Per i dispositivi con isolamento dello spazio dei nomi del linker VNDK-SP
    ld.config.legacy.txt ld.config.legacy.txt Per i dispositivi legacy con Android 7.x o versioni precedenti
  • Rimuovi android.hardware.graphics.allocator@2.0.so.
  • Sono state aggiunte le partizioni product e odm.