Espacio de nombres del vinculador

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

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

El mecanismo de espacio de nombres del vinculador puede resolver estos dos desafíos. El vinculador dinámico proporciona este mecanismo. Puede aislar las bibliotecas compartidas en diferentes espacios de nombres del vinculador para que las bibliotecas con el mismo nombre de biblioteca, pero con símbolos diferentes, no entren en conflicto.

Por otro lado, el mecanismo de espacio de nombres del vinculador proporciona la flexibilidad para que un espacio de nombres del vinculador pueda exportar algunas bibliotecas compartidas y que las use otro espacio de nombres del vinculador. Estas bibliotecas compartidas exportadas pueden convertirse en interfaces de programación de aplicaciones que son públicas para otros programas y, al mismo tiempo, ocultar sus detalles de implementación dentro de sus espacios de nombres de vinculador.

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 de vinculador para que los módulos del framework puedan depender de /system/lib[64]/libcutils.so y las bibliotecas compartidas de SP-HAL puedan 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 que exporta un espacio de nombres del vinculador y se importa a muchos espacios de nombres del vinculador. 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 la implementación y, al mismo tiempo, proporciona las interfaces públicas.

Cómo funciona

El vinculador 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 en el que reside el llamador y trata de 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, le solicita al espacio de nombres del vinculador vinculado bibliotecas compartidas exportadas.

Formato del 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 de la siguiente manera:

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 lo siguiente:

  • Varias propiedades de asignación de directorios y secciones al principio para que el vinculador dinámico seleccione la sección efectiva.
  • Varias secciones de configuración de espacios de nombres del vinculador:
    • Cada sección contiene varios espacios de nombres (vértices del gráfico) y varios vínculos de resguardo entre espacios de nombres (arcos del gráfico).
    • Cada espacio de nombres tiene su propio aislamiento, sus propias rutas de búsqueda, sus rutas permitidas y su configuración de visibilidad.

En las siguientes tablas, se describe el significado de cada propiedad en detalle.

Propiedad de asignación de sección de directorio

Propiedad Descripción Ejemplo

dir.name

Es una ruta de acceso 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 vinculador. Puede haber dos (o más) propiedades que tengan el mismo name, pero que 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 la 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 de [system].

namespace.name.links

Una lista de espacios de nombres de resguardo separados por comas.

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 de resguardo. El espacio de nombres especificado al comienzo de la lista tiene mayor prioridad.

namespace.sphal.links = default,vndk

Si una biblioteca compartida o un ejecutable solicitan 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.

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.

Por último, si fallan todos los intentos, el vinculador dinámico muestra un error.

namespace.name.link.other.shared_libs

Es una lista de bibliotecas compartidas separadas por dos puntos que se pueden buscar en los espacios de nombres other cuando no se pueden encontrar en el espacio de nombres name.

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

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

Esto indica que el vínculo de resguardo solo acepta libc.so o libm.so como el nombre de la biblioteca solicitada. El vinculador dinámico ignora el vínculo de resguardo del espacio de nombres sphal al espacio de nombres default si el nombre de la biblioteca solicitado no es libc.so ni libm.so.

namespace.name.link.other.allow_all_shared_libs

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

No se puede usar esta propiedad con namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

Esto indica que todos los nombres de bibliotecas pueden recorrer el vínculo de resguardo del espacio de nombres vndk al sphal.

Propiedades del espacio de nombres

Propiedad Descripción Ejemplo
namespace.name.isolated

Es un valor booleano que indica si el vinculador dinámico debe verificar dónde reside la biblioteca compartida.

Si isolated es true, solo se pueden cargar las bibliotecas compartidas que están en uno de los directorios search.paths (sin incluir subdirectorios) o que están debajo de uno de los directorios permitted.paths (incluidos los subdirectorios).

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

namespace.sphal.isolated = true

Esto indica que solo se pueden cargar las bibliotecas compartidas en search.paths o en permitted.paths 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 las entradas dlopen() o DT_NEEDED no especifican la ruta de acceso completa. El directorio especificado al principio de la lista tiene mayor prioridad.

Cuando isolated es true, se pueden cargar las bibliotecas compartidas que están en uno de los directorios search.paths (sin incluir subdirectorios), independientemente de la propiedad permitted.paths.

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

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

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

namespace.name.asan.search.paths

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

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 se habilita ASan, el vinculador dinámico busca primero /data/asan/system/${LIB} y, luego, /system/${LIB}.

namespace.name.permitted.paths

Es una lista de directorios (incluidos los subdirectorios) separados por dos puntos en la que el vinculador dinámico puede cargar las bibliotecas compartidas (además de search.paths) cuando 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 /system/${LIB}/libc.so y /system/${LIB}/vndk/libutils.so.

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

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

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

Por ejemplo, sin 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

Es una lista de directorios separados por dos puntos en los que el vinculador dinámico puede cargar las bibliotecas compartidas cuando se habilita ASan.

namespace.name.permitted.paths se ignora cuando se habilita ASan.

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

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

namespace.name.visible

Es un valor booleano que indica si el programa (distinto de 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 muestra el identificador si el espacio de nombres existe.

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

namespace.sphal.visible = true

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

Creación del espacio de nombres del vinculador

En Android 11, la configuración del vinculador se crea en el 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 inicio en función del entorno de ejecución, que incluye los siguientes elementos:

  • Si el dispositivo admite VNDK
  • Versión de VNDK de destino de la partición del proveedor
  • Versión del VNDK de la partición de producto
  • Módulos de 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 dependencias, se genera la configuración del vinculador que refleja estos cambios. Puedes encontrar más detalles para crear la configuración del vinculador en ${android-src}/system/linkerconfig.

Aislamiento del espacio de nombres del vinculador

Existen 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 inicio.

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

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 del vinculador dinámico cuando PRODUCT_TREBLE_LINKER_NAMESPACES sea true.

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

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

Configuración del VNDK

La configuración de VNDK aísla las dependencias de bibliotecas compartidas 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 de la siguiente manera:

  • Procesos del framework

    • Se crean los 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 de VNDK-SP cargadas en el espacio de nombres vndk
  • Procesos de proveedores

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

A continuación, se ilustra la relación entre los espacios de nombres del vinculador.

Gráfico del espacio de nombres del vinculador descrito en la configuración del VNDK

Figura 1: Aislamiento del espacio de nombres del vinculador (configuración de VNDK)

En la imagen anterior, LL-NDK y VNDK-SP significan 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

Puedes 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 se configura para aislar las bibliotecas compartidas de SP-HAL y VNDK-SP de modo que sus símbolos no entren en conflicto con otras bibliotecas compartidas del framework. A continuación, se muestra la relación entre los espacios de nombres del vinculador.

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 está en la configuración)
    • libsync.so
    • libvndksupport.so
    • libz.so (se trasladó 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

En la siguiente tabla, se indica la configuración de los espacios de nombres para los procesos del framework, extraído de la sección [system] de la configuración del 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 el kernel de 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

En la siguiente tabla, se presenta la configuración de espacios de nombres para los procesos del proveedor, 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} (obsoleta)
/product/${LIB} (obsoleta)
isolated false

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

Historial del documento

Cambios en Android 11

  • En Android 11, los archivos ld.config.*.txt estáticos se quitan de la base de código y LinkerConfig los genera en el entorno 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.
  • Reemplaza PRODUCT_FULL_TREBLE por un PRODUCT_TREBLE_LINKER_NAMESPACES más específico.
  • Android 9 cambia los nombres de los siguientes archivos de configuración del vinculador dinámico.
    Android 8.x Android 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 del vinculador VNDK-SP
    ld.config.legacy.txt ld.config.legacy.txt Para dispositivos heredados que ejecutan Android 7.x o versiones anteriores
  • Se quita android.hardware.graphics.allocator@2.0.so.
  • Se agregaron las particiones product y odm.