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 procesos de marco. Debería haber algunos mecanismos para evitar conflictos de símbolos.
  • dlopen() y android_dlopen_ext() pueden introducir algunas dependencias en 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 pueden resolverse mediante el mecanismo del espacio de nombres del vinculador . Este mecanismo lo proporciona el enlazador dinámico. 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 del espacio de nombres del vinculador proporciona la flexibilidad para que algunas bibliotecas compartidas puedan ser exportadas por un espacio de nombres del vinculador y utilizadas por 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 ocultan sus detalles de implementación dentro de los espacios de nombres de sus vinculadores.

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 enlazadores para que los módulos del marco puedan depender de /system/lib[64]/libcutils.so y las bibliotecas compartidas 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 mediante 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 implementación al tiempo que proporciona las interfaces públicas.

¿Como 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 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 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 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 asignación de sección 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 de gráficos) y varios enlaces alternativos entre espacios de nombres (arcos de gráficos).
    • Cada espacio de nombres tiene su propio aislamiento, rutas de búsqueda, rutas permitidas y configuración de visibilidad.

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

Propiedad de asignación 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 vinculador. 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 [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 vinculador 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 other espacios de nombres cuando esas bibliotecas no se pueden encontrar en el espacio name .

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

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

Esto indica que el enlace alternativo acepta solo libc.so o libm.so como nombre de biblioteca solicitado. El vinculador dinámico ignora el vínculo 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 se pueden buscar todas las bibliotecas compartidas en el other espacio de nombres cuando esas bibliotecas no se pueden encontrar en el espacio name .

Esta propiedad no se puede utilizar 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 pasar por el enlace alternativo desde 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 vinculador 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 (excluidos los subdirectorios) o en uno de los directorios permitted.paths (incluidos los subdirectorios).

Si isolated es false (predeterminado), el vinculador 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 permitted.paths se 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 a funciones a 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 , las bibliotecas compartidas que se encuentran en uno de los directorios search.paths (excluidos 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 vinculador 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 vinculador dinámico busca /data/asan/system/${LIB} primero y luego busca /system/${LIB} .

namespace. name . permitted.paths

Una lista de directorios (incluidos subdirectorios) separados por dos puntos donde 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 tanto /system/${LIB}/libc.so como /system/${LIB}/vndk/libutils.so .

Si isolated es false , permitted.paths se ignoran 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 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 vinculador dinámico puede cargar las bibliotecas compartidas cuando ASan está habilitado.

namespace. name . permitted.paths se ignora 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 el espacio de nombres existe.

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 vinculador que tiene un vínculo alternativo a este espacio de nombres, o (2) las solicitan otras bibliotecas compartidas o archivos 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 de 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 es compatible con VNDK
  • Versión VNDK de destino de la partición del proveedor
  • Versión VNDK de la partición del producto
  • Módulos APEX instalados

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

Aislamiento del espacio de nombres del vinculador

Hay tres tipos de configuración. Dependiendo del 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 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 para el vinculador 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 dinámico completo del vinculador. 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 VNDK es la configuración predeterminada y se recomienda encarecidamente habilitar el aislamiento dinámico completo del vinculador configurando BOARD_VNDK_VERSION en current .

Configuración 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 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 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 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 .

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 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 del dispositivo.

Configuración 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 del espacio de nombres del vinculador descrito en la configuración de VNDK Lite
Figura 2. Aislamiento del espacio de nombres del vinculador (configuración 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 espacios de nombres para procesos de marco, que está extraída 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 está extraída 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 del 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 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 están aisladas 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 del 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 con Android 7.x o inferior
  • Elimine android.hardware.graphics.allocator@2.0.so .
  • Se agregan particiones product y odm .