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 momento de la compilación y pueden ser difíciles de detectar con el análisis estático.

Estos dos desafíos se pueden resolver con el mecanismo del espacio de nombres del vinculador. 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, pero con diferentes símbolos, no entren en conflicto.

Por otro lado, el mecanismo de espacio de nombres del vinculador proporciona la flexibilidad necesaria para que un espacio de nombres del vinculador pueda exportar algunas bibliotecas compartidas y otro espacio de nombres del vinculador pueda usarlas. Estas bibliotecas compartidas exportadas pueden convertirse en interfaces de programación de aplicaciones que son públicas para otros programas y, al mismo tiempo, ocultan los detalles de implementación dentro de sus espacios de nombres del 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 del 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 se exporta desde un espacio de nombres del vinculador y se importa en 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 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 de 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 las 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 secciones de directorio 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 respaldo entre espacios de nombres (arcos del gráfico).
    • Cada espacio de nombres tiene su propio aislamiento, rutas de búsqueda, rutas permitidas y 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 la 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. Es posible que haya 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

Es 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

Es una lista separada por comas de los espacios de nombres de resguardo.

Si no se encuentra 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 devuelve un error.

namespace.name.link.other.shared_libs

Es una lista separada por dos puntos de las bibliotecas compartidas en las que se puede buscar en los espacios de nombres de other cuando esas bibliotecas no se encuentran en el espacio de nombres de 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 default si el nombre de la biblioteca solicitada no es libc.so o 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.

Esta propiedad no se puede usar 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 desde el espacio de nombres vndk al espacio de nombres 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 se encuentra la biblioteca compartida.

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

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

namespace.sphal.isolated = true

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

namespace.name.search.paths

Es una lista de directorios separados por dos puntos en los que se buscarán bibliotecas compartidas.

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

Cuando isolated es true, se pueden cargar las bibliotecas compartidas que se encuentran en uno de los directorios search.paths (sin incluir los 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 /system/${LIB} para las bibliotecas compartidas.

namespace.name.asan.search.paths

Lista de directorios separados por dos puntos en los que se buscarán bibliotecas compartidas cuando se habilite AddressSanitizer (ASan).

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

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

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

namespace.name.permitted.paths

Lista de directorios (incluidos los subdirectorios) separados por dos puntos en los 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 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 aislado 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 la que el vinculador dinámico puede cargar las bibliotecas compartidas cuando ASan está habilitado.

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 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

Es 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 solo se pueden cargar en este espacio de nombres si (1) otro espacio de nombres del vinculador que tiene un vínculo de resguardo a este espacio de nombres las solicita o (2) 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 devolver 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 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 según el entorno de ejecución, que incluye los siguientes elementos:

  • Si el dispositivo admite el VNDK
  • Versión del VNDK de destino de la partición del proveedor
  • Versión del VNDK de la partición de 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 dependencias, se genera una 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 los dispositivos lanzados con Android 9 o versiones posteriores
Vacío VNDK Lite Obligatorio para los dispositivos lanzados con Android 8.x
false Vacío Legacy Para dispositivos que no son Treble

La configuración de VNDK Lite aísla las bibliotecas compartidas de 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 es true.

La configuración del 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. Esto 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 del VNDK es la predeterminada, y se recomienda habilitar el aislamiento completo del vinculador dinámico estableciendo BOARD_VNDK_VERSION en current.

Configuración del VNDK

La configuración del 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 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 del 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 del proveedor se cargan en el espacio de nombres default.
    • Las bibliotecas compartidas de VNDK y VNDK-SP se cargan en el espacio de nombres vndk.
    • El 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 de espacio de nombres del vinculador descrito en la configuración del VNDK

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

En la imagen anterior, 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

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 está configurado 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 del espacio de nombres del vinculador que se describe 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 muestra la configuración de los espacios de nombres para los procesos del framework, 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 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 extrajo 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

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

Historial del documento

Cambios en Android 11

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

Cambios en Android 9

  • En Android 9, se agrega el espacio de nombres del vinculador vndk a los procesos del proveedor y las bibliotecas compartidas del 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 de tiempo de ejecución
    ld.config.txt ld.config.vndk_lite.txt Para dispositivos con aislamiento del espacio de nombres del vinculador VNDK-SP
    ld.config.legacy.txt ld.config.legacy.txt Para dispositivos heredados con Android 7.x o versiones anteriores
  • Se quita android.hardware.graphics.allocator@2.0.so.
  • Se agregaron las particiones product y odm.