Espacio de nombres del enlazador

El enlazador dinámico aborda dos desafíos en el diseño de Treble VNDK:

  • Las bibliotecas compartidas SP-HAL y sus dependencias, incluidas las bibliotecas VNDK-SP, se cargan en los procesos del marco. Debe haber algunos mecanismos para prevenir conflictos de símbolos.
  • dlopen() y android_dlopen_ext() pueden introducir algunas dependencias de tiempo de ejecución que no son visibles en el momento de la compilación y pueden ser difíciles de detectar mediante el análisis estático.

Estos dos desafíos se pueden resolver mediante el mecanismo de espacio de nombres del enlazador . Este mecanismo lo proporciona el enlazador dinámico. Puede aislar las bibliotecas compartidas en diferentes espacios de nombres del enlazador para que las bibliotecas con el mismo nombre de biblioteca pero con diferentes símbolos no entren en conflicto.

Por otro lado, el mecanismo del espacio de nombres del enlazador proporciona la flexibilidad para que un espacio de nombres del enlazador pueda exportar algunas bibliotecas compartidas y usarlas otro espacio de nombres del enlazador. Estas bibliotecas compartidas exportadas pueden convertirse en interfaces de programación de aplicaciones que son públicas para otros programas mientras ocultan sus detalles de implementación dentro de los espacios de nombres de sus enlazadores.

Por ejemplo, /system/lib[64]/libcutils.so y /system/lib[64]/vndk-sp-${VER}/libcutils.so son dos bibliotecas compartidas. Estas dos bibliotecas pueden tener símbolos diferentes. Se cargan en diferentes espacios de nombres del enlazador para que los módulos del marco puedan depender de /system/lib[64]/libcutils.so y las bibliotecas compartidas SP-HAL pueden depender de /system/lib[64]/vndk-sp-${VER}/libcutils.so .

Por otro lado, /system/lib[64]/libc.so es un ejemplo de una biblioteca pública exportada por un espacio de nombres del enlazador e importada en muchos espacios de nombres del enlazador. Las dependencias de /system/lib[64]/libc.so , como libnetd_client.so , se cargan en el espacio de nombres en el que reside /system/lib[64]/libc.so . Otros espacios de nombres no tendrán acceso a esas dependencias. Este mecanismo encapsula los detalles de implementación mientras proporciona las interfaces públicas.

¿Como funciona?

El enlazador dinámico es responsable de cargar las bibliotecas compartidas especificadas en las entradas DT_NEEDED o las bibliotecas compartidas especificadas por el argumento de dlopen() o android_dlopen_ext() . En ambos casos, el vinculador dinámico encuentra el espacio de nombres del vinculador donde reside la persona que llama e intenta cargar las dependencias en el mismo espacio de nombres del vinculador. Si el vinculador dinámico no puede cargar la biblioteca compartida en el espacio de nombres del vinculador especificado, solicita al espacio de nombres del vinculador vinculado las bibliotecas compartidas exportadas.

Formato de archivo de configuración

El formato del archivo de configuración se basa en el formato de archivo INI. Un archivo de configuración típico se ve así:

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}

El archivo de configuración incluye:

  • Varias propiedades de mapeo de sección de directorio al principio para que el enlazador dinámico seleccione la sección efectiva.
  • Varias secciones de configuración de espacios de nombres del enlazador:
    • Cada sección contiene varios espacios de nombres (vértices de gráficos) y varios enlaces alternativos entre espacios de nombres (arcos de gráficos).
    • Cada espacio de nombres tiene su propia configuración de aislamiento, rutas de búsqueda, rutas permitidas y visibilidad.

Las siguientes tablas describen el significado de cada propiedad en detalle.

Propiedad de mapeo de sección de directorio

Propiedad Descripción Ejemplo

dir. name

Una ruta a un directorio al que se aplica la sección [ name ] .

Cada propiedad asigna los ejecutables del directorio a una sección de configuración de espacios de nombres del enlazador. Puede haber dos (o más) propiedades que tengan el mismo name pero apunten a directorios diferentes.

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

Esto indica que la configuración especificada en la sección [system] se aplica a los ejecutables que se cargan desde /system/bin o /system/xbin .

La configuración especificada en la sección [vendor] se aplica a los ejecutables que se cargan desde /vendor/bin .

Propiedades de relación

Propiedad Descripción Ejemplo
additional. namespaces

Una lista separada por comas de espacios de nombres adicionales (además del espacio de nombres default ) para la sección.

additional. namespaces = sphal, vndk

Esto indica que hay tres espacios de nombres ( default , sphal y vndk ) en la configuración del [system] .

namespace. name . links

Una lista separada por comas de espacios de nombres alternativos.

Si no se puede encontrar una biblioteca compartida en el espacio de nombres actual, el vinculador dinámico intenta cargar la biblioteca compartida desde los espacios de nombres alternativos. El espacio de nombres especificado al principio de la lista tiene mayor prioridad.

namespace. sphal. links = default, vndk

Si una biblioteca compartida o un ejecutable solicita una biblioteca compartida que no se puede cargar en el espacio de nombres sphal , el vinculador dinámico intenta cargar la biblioteca compartida desde el espacio de nombres default .

Y luego, si la biblioteca compartida tampoco se puede cargar desde el espacio de nombres default , el vinculador dinámico intenta cargar la biblioteca compartida desde el espacio de nombres vndk .

Finalmente, si todos los intentos fallan, el enlazador dinámico devuelve un error.

namespace. name . link. other . shared_libs

Una lista separada por dos puntos de bibliotecas compartidas que se pueden buscar en los other espacios de nombres cuando esas bibliotecas no se pueden encontrar en el espacio de name .

Esta propiedad no se puede usar con el espacio de namespace. name . link. other . allow_all_shared_libs .

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

Esto indica que el enlace alternativo solo acepta libc.so o libm.so como el nombre de biblioteca solicitado. El enlazador dinámico ignora el enlace alternativo de sphal al espacio de nombres default si el nombre de la biblioteca solicitada no es libc.so o libm.so .

namespace. name . link. other . allow_all_shared_libs

Un valor booleano que indica si todas las bibliotecas compartidas se pueden buscar en el other espacio de nombres cuando esas bibliotecas no se pueden encontrar en el espacio de name .

Esta propiedad no se puede usar con el espacio de namespace. name . link. other . shared_libs .

namespace. vndk. link. sphal. allow_all_shared_libs = true

Esto indica que todos los nombres de biblioteca pueden pasar por el enlace alternativo de vndk al espacio de nombres sphal .

Propiedades del espacio de nombres

Propiedad Descripción Ejemplo
namespace. name . isolated

Un valor booleano que indica si el enlazador dinámico debe comprobar dónde reside la biblioteca compartida.

Si isolated es true , solo se pueden cargar las bibliotecas compartidas que se encuentran en uno de los directorios search.paths (excluyendo los subdirectorios) o en uno de los directorios permitted.paths (incluidos los subdirectorios).

Si isolated es false (predeterminado), el enlazador dinámico no verifica la ruta de las bibliotecas compartidas.

namespace. sphal. isolated = true

Esto indica que solo las bibliotecas compartidas en search.paths o en search.paths permitted.paths pueden cargar en el espacio de nombres sphal .

namespace. name . search.paths

Una lista de directorios separados por dos puntos para buscar bibliotecas compartidas.

Los directorios especificados en search.paths se anteponen al nombre de la biblioteca solicitada si las llamadas de función a dlopen() o las entradas DT_NEEDED no especifican la ruta completa. El directorio especificado al principio de la lista tiene mayor prioridad.

Cuando isolated es true , las bibliotecas compartidas que se encuentran en uno de los directorios search.paths (excluyendo los subdirectorios) se pueden cargar independientemente de la propiedad permitted.paths .

Por ejemplo, si search.paths es /system/${LIB} y permitted.paths está vacío, /system/${LIB}/libc.so se puede cargar pero /system/${LIB}/vndk/libutils.so no se puede cargar

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

Esto indica que el enlazador dinámico busca /system/${LIB} bibliotecas compartidas.

namespace. name . asan.search.paths

Una lista de directorios separados por dos puntos para buscar bibliotecas compartidas cuando AddressSanitizer (ASan) está habilitado.

namespace. name . search.paths se ignora cuando ASan está habilitado.

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

Esto indica que cuando ASan está habilitado, el enlazador dinámico busca /data/asan/system/${LIB} primero y luego busca /system/${LIB} .

namespace. name . permitted.paths

Una lista de directorios separados por dos puntos (incluidos los subdirectorios) donde el enlazador dinámico puede cargar las bibliotecas compartidas (además de search.paths ) cuando está isolated es true .

También se pueden cargar las bibliotecas compartidas que se encuentran en los subdirectorios de permitted.paths . Por ejemplo, si permitted.paths es /system/${LIB} , se pueden cargar tanto /system/${LIB}/libc.so como /system/${LIB}/vndk/libutils.so .

Si isolated es false , se ignoran las rutas permitted.paths y se emite una advertencia.

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

Esto indica que las bibliotecas compartidas en /system/${LIB}/hw se pueden cargar en el espacio de nombres default aislado.

Por ejemplo, sin las rutas permitted.paths , libaudiohal.so no puede cargar /system/${LIB}/hw/audio.a2dp.default.so en el espacio de nombres default .

namespace. name . asan.permitted.paths

Una lista de directorios separados por dos puntos donde el enlazador dinámico puede cargar las bibliotecas compartidas cuando ASan está habilitado.

namespace. name . permitted.paths Las rutas namespace. name . permitted.paths se ignoran cuando ASan está habilitado.

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

Esto indica que cuando ASan está habilitado, las bibliotecas compartidas en /data/asan/system/${LIB}/hw o /system/${LIB}/hw se pueden cargar en el espacio de nombres default aislado.

namespace. name . visible

Un valor booleano que indica si el programa (que no sea libc ) puede obtener un identificador de espacio de nombres del vinculador con android_get_exported_namespace() y abrir una biblioteca compartida en el espacio de nombres del vinculador pasando el identificador a android_dlopen_ext() .

Si visible es true , android_get_exported_namespace() siempre devuelve el identificador si existe el espacio de nombres.

Si visible es false (predeterminado), android_get_exported_namespace() siempre devuelve NULL , independientemente de la presencia del espacio de nombres. Las bibliotecas compartidas se pueden cargar en este espacio de nombres solo si (1) las solicita otro espacio de nombres del vinculador que tiene un enlace alternativo a este espacio de nombres, o (2) las solicitan otras bibliotecas compartidas o ejecutables en este espacio de nombres.

namespace. sphal. visible = true

Esto indica que android_get_exported_namespace("sphal") puede devolver un identificador de espacio de nombres de vinculador válido.

Creación del espacio de nombres del enlazador

En Android 11, la configuración del enlazador se crea en tiempo de ejecución en /linkerconfig en lugar de usar archivos de texto sin formato en ${android-src}/system/core/rootdir/etc . La configuración se genera en el momento del arranque en función del entorno de tiempo de ejecución, que incluye los siguientes elementos:

  • Si el dispositivo es compatible con VNDK
  • Versión de VNDK de destino de la partición del proveedor
  • Versión de VNDK de la partición del producto
  • Módulos APEX instalados

La configuración del vinculador se crea resolviendo las dependencias entre los espacios de nombres del vinculador. Por ejemplo, si hay actualizaciones en los módulos APEX que incluyen actualizaciones de dependencia, la configuración del enlazador se genera reflejando estos cambios. Se pueden encontrar más detalles para crear la configuración del enlazador en ${android-src}/system/linkerconfig .

Aislamiento del espacio de nombres del enlazador

Hay tres tipos de configuración. Según el valor de PRODUCT_TREBLE_LINKER_NAMESPACES y BOARD_VNDK_VERSION en BoardConfig.mk , la configuración correspondiente se genera en el momento del arranque.

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
Configuración seleccionada Requisito VTS
true current VNDK Obligatorio para dispositivos lanzados con Android 9 o superior
Vacío VNDK Lite Obligatorio para dispositivos lanzados con Android 8.x
false Vacío Legacy Para dispositivos que no son de agudos

La configuración de VNDK Lite aísla las bibliotecas compartidas SP-HAL y VNDK-SP. En Android 8.0, este debe ser el archivo de configuración para el enlazador dinámico cuando PRODUCT_TREBLE_LINKER_NAMESPACES es true .

La configuración de VNDK también aísla las bibliotecas compartidas SP-HAL y VNDK-SP. Además, esta configuración proporciona el aislamiento completo del enlazador dinámico. Garantiza que los módulos en la partición del sistema no dependan de las bibliotecas compartidas en las particiones del proveedor y viceversa.

En Android 8.1 o superior, la configuración de VNDK es la configuración predeterminada y se recomienda habilitar el aislamiento completo del enlazador dinámico configurando BOARD_VNDK_VERSION en current .

Configuración de VNDK

La configuración de VNDK aísla las dependencias de la biblioteca compartida entre la partición del sistema y las particiones del proveedor. En comparación con las configuraciones mencionadas en la subsección anterior, las diferencias se describen a continuación:

  • Procesos marco

    • Se crean espacios de nombres default , vndk , sphal y rs .
    • Todos los espacios de nombres están aislados.
    • Las bibliotecas compartidas del sistema se cargan en el espacio de nombres default .
    • Los SP-HAL se cargan en el espacio de nombres sphal .
    • Bibliotecas compartidas VNDK-SP cargadas en el espacio de nombres vndk .
  • Procesos de proveedores

    • Se crean espacios de nombres default , vndk y system .
    • El espacio de nombres default está aislado.
    • Las bibliotecas compartidas del proveedor se cargan en el espacio de nombres default .
    • Las bibliotecas compartidas VNDK y VNDK-SP se cargan en el espacio de nombres vndk .
    • LL-NDK y sus dependencias se cargan en el espacio de nombres del system .

La relación entre los espacios de nombres del enlazador se ilustra a continuación.

Gráfico de espacio de nombres del vinculador descrito en la configuración de VNDK
Figura 1. Aislamiento del espacio de nombres del vinculador (configuración de VNDK)

En la imagen de arriba, LL-NDK y VNDK-SP representan las siguientes bibliotecas compartidas:

  • 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

Puede encontrar más detalles en /linkerconfig/ld.config.txt desde el dispositivo.

Configuración de VNDK Lite

A partir de Android 8.0, el vinculador dinámico está configurado para aislar las bibliotecas compartidas SP-HAL y VNDK-SP de modo que sus símbolos no entren en conflicto con otras bibliotecas compartidas del marco. La relación entre los espacios de nombres del enlazador se muestra a continuación.

Gráfico de espacio de nombres del vinculador descrito en la configuración de VNDK Lite
Figura 2. Aislamiento del espacio de nombres del vinculador (configuración de VNDK Lite)

LL-NDK y VNDK-SP representan las siguientes bibliotecas compartidas:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libstdc++.so (no en la configuración)
    • libsync.so
    • libvndksupport.so
    • libz.so (movido a VNDK-SP en la configuración)
  • 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 siguiente tabla enumera la configuración de los espacios de nombres para los procesos del marco, que se extrajo de la sección [system] en la configuración de VNDK Lite.

espacio de nombres Propiedad Valor
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 (para 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 (para 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 (para kernel RS compilado)
isolated true
visible true
links default,vndk
link.default.shared_libs LL-NDK
libmediandk.so
libft2.so
link.vndk.shared_libs VNDK-SP

La siguiente tabla presenta la configuración de espacios de nombres para procesos de proveedores, que se extrae de la sección [vendor] en la configuración de VNDK Lite.

espacio de nombres Propiedad Valor
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} (obsoleto)
/product/${LIB} (obsoleto)
isolated false

Se pueden encontrar más detalles en /linkerconfig/ld.config.txt desde el dispositivo.

Historia del documento

Cambios en Android 11

  • En Android 11, los archivos estáticos ld.config.*.txt se eliminan del código base y, en su lugar, LinkerConfig los genera en tiempo de ejecución.

Cambios en Android 9

  • En Android 9, el espacio de nombres del vinculador vndk se agrega a los procesos del proveedor y las bibliotecas compartidas de VNDK se aíslan del espacio de nombres del vinculador predeterminado.
  • Reemplace PRODUCT_FULL_TREBLE con PRODUCT_TREBLE_LINKER_NAMESPACES más específicos.
  • Android 9 cambia los nombres de los siguientes archivos de configuración del vinculador dinámico.
    Android 8.x androide 9 Descripción
    ld.config.txt.in ld.config.txt Para dispositivos con aislamiento de espacio de nombres del vinculador en tiempo de ejecución
    ld.config.txt ld.config.vndk_lite.txt Para dispositivos con aislamiento de espacio de nombres de vinculador VNDK-SP
    ld.config.legacy.txt ld.config.legacy.txt Para dispositivos heredados con Android 7.x o inferior
  • Quite android.hardware.graphics.allocator@2.0.so .
  • Se agregan las particiones product y odm .