Namespace do vinculador

O vinculador dinâmico enfrenta dois desafios no design do Treble VNDK:

  • As bibliotecas compartilhadas do SP-HAL e as dependências, incluindo as bibliotecas do VNDK-SP, são carregadas nos processos do framework. Deve haver alguns mecanismos para evitar conflitos de símbolos.
  • dlopen() e android_dlopen_ext() podem introduzir algumas dependências de execução que não estão visíveis no momento da criação e podem ser difíceis de detectar usando a análise estática.

Esses dois desafios podem ser resolvidos pelo mecanismo de namespace do vinculador. Esse mecanismo é fornecido pelo vinculador dinâmico. Ele pode isolar as bibliotecas compartilhadas em diferentes namespaces de vinculador para que bibliotecas com o mesmo nome, mas com símbolos diferentes, não entrem em conflito.

Por outro lado, o mecanismo de namespace do vinculador oferece a flexibilidade para que algumas bibliotecas compartilhadas possam ser exportadas por um namespace do vinculador e usadas por outro namespace do vinculador. Essas bibliotecas compartilhadas exportadas podem se tornar interfaces de programação de aplicativos que são públicas para outros programas, ocultam os detalhes de implementação nos namespaces do vinculador.

Por exemplo, /system/lib[64]/libcutils.so e /system/lib[64]/vndk-sp-${VER}/libcutils.so são duas bibliotecas compartilhadas. Essas duas bibliotecas podem ter símbolos diferentes. Eles são carregados em diferentes namespaces de vinculador para que os módulos do framework possam depender de /system/lib[64]/libcutils.so e as bibliotecas compartilhadas do SP-HAL possam depender de /system/lib[64]/vndk-sp-${VER}/libcutils.so.

Por outro lado, /system/lib[64]/libc.so é um exemplo de uma biblioteca pública exportada por um namespace de vinculador e importada em vários namespaces de vinculador. As dependências de /system/lib[64]/libc.so, como libnetd_client.so, são carregadas no namespace em que /system/lib[64]/libc.so reside. Outros namespaces não terão acesso a essas dependências. Esse mecanismo encapsula os detalhes de implementação e fornece as interfaces públicas.

Como funciona

O vinculador dinâmico é responsável por carregar as bibliotecas compartilhadas especificadas nas entradas DT_NEEDED ou as bibliotecas compartilhadas especificadas pelo argumento de dlopen() ou android_dlopen_ext(). Em ambos os casos, o vinculador dinâmico encontra o namespace do vinculador em que o autor da chamada reside e tenta carregar as dependências no mesmo namespace do vinculador. Se o vinculador dinâmico não conseguir carregar a biblioteca compartilhada no namespace de vinculador especificado, ele vai pedir ao namespace do vinculador vinculado as bibliotecas compartilhadas exportadas.

Formato do arquivo de configurações

O formato do arquivo de configuração é baseado no formato INI. Um arquivo de configuração típico tem esta aparência:

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}

O arquivo de configuração inclui:

  • Várias propriedades de mapeamento de seção de diretório no início para que o vinculador dinâmico selecione a seção efetiva.
  • Várias seções de configuração de namespaces do vinculador:
    • Cada seção contém vários namespaces (vértices do gráfico) e vários links substitutos entre namespaces (arcos do gráfico).
    • Cada namespace tem o próprio isolamento, caminhos de pesquisa, caminhos permitidos e configurações de visibilidade.

As tabelas abaixo descrevem o significado de cada propriedade em detalhes.

Propriedade de mapeamento de seção do diretório

Propriedade Descrição Exemplo

dir.name

Um caminho para um diretório ao qual a seção [name] se aplica.

Cada propriedade mapeia os executáveis no diretório para uma seção de configuração de namespaces do vinculador. Pode haver duas (ou mais) propriedades que têm o mesmo name, mas apontam para diretórios diferentes.

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

Isso indica que a configuração especificada na seção [system] se aplica aos executáveis carregados de /system/bin ou /system/xbin.

A configuração especificada na seção [vendor] se aplica aos executáveis carregados de /vendor/bin.

Propriedades de relação

Propriedade Descrição Exemplo
additional.namespaces

Uma lista separada por vírgulas de namespaces adicionais (além do namespace default) para a seção.

additional.namespaces = sphal,vndk

Isso indica que há três namespaces (default, sphal e vndk) na configuração [system].

namespace.name.links

Uma lista separada por vírgulas de namespaces substitutos.

Se uma biblioteca compartilhada não puder ser encontrada no namespace atual, o vinculador dinâmico tentará carregar a biblioteca compartilhada dos namespaces substitutos. O namespace especificado no início da lista tem prioridade maior.

namespace.sphal.links = default,vndk

Se uma biblioteca compartilhada ou um executável solicitar uma biblioteca compartilhada que não possa ser carregada no namespace sphal, o vinculador dinâmico tentará carregar a biblioteca compartilhada do namespace default.

Se a biblioteca compartilhada não puder ser carregada do namespace default, o vinculador dinâmico vai tentar carregar a biblioteca compartilhada do namespace vndk.

Por fim, se todas as tentativas falharem, o vinculador dinâmico vai retornar um erro.

namespace.name.link.other.shared_libs

Uma lista separada por dois-pontos de bibliotecas compartilhadas que podem ser pesquisadas nos namespaces other quando elas não podem ser encontradas no namespace name.

Essa propriedade não pode ser usada com namespace.name.link.other.allow_all_shared_libs.

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

Isso indica que o link alternativo aceita apenas libc.so ou libm.so como o nome da biblioteca solicitada. O vinculador dinâmico ignora o link substituto de sphal para o namespace default se o nome da biblioteca solicitado não for libc.so ou libm.so.

namespace.name.link.other.allow_all_shared_libs

Um valor booleano que indica se todas as bibliotecas compartilhadas podem ser pesquisadas no namespace other quando não podem ser encontradas no namespace name.

Essa propriedade não pode ser usada com namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

Isso indica que todos os nomes de biblioteca podem usar o link substituto do namespace vndk para sphal.

Propriedades de namespace

Propriedade Descrição Exemplo
namespace.name.isolated

Um valor booleano que indica se o vinculador dinâmico precisa verificar onde a biblioteca compartilhada está.

Se isolated for true, apenas as bibliotecas compartilhadas que estiverem em um dos diretórios search.paths (exceto subdiretórios) ou abaixo de um dos diretórios permitted.paths (incluindo subdiretórios) poderão ser carregadas.

Se isolated for false (padrão), o vinculador dinâmico não vai verificar o caminho das bibliotecas compartilhadas.

namespace.sphal.isolated = true

Isso indica que apenas as bibliotecas compartilhadas em search.paths ou em permitted.paths podem ser carregadas no namespace sphal.

namespace.name.search.paths

Uma lista de diretórios separada por dois-pontos para pesquisar bibliotecas compartilhadas.

Os diretórios especificados em search.paths são adicionados ao nome da biblioteca solicitada se as chamadas de função para dlopen() ou as entradas DT_NEEDED não especificarem o caminho completo. O diretório especificado no início da lista tem prioridade mais alta.

Quando isolated é true, as bibliotecas compartilhadas que estão em um dos diretórios search.paths (exceto subdiretórios) podem ser carregadas, independentemente da propriedade permitted.paths.

Por exemplo, se search.paths for /system/${LIB} e permitted.paths estiver vazio, /system/${LIB}/libc.so poderá ser carregado, mas /system/${LIB}/vndk/libutils.so não.

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

Isso indica que o vinculador dinâmico procura /system/${LIB} para bibliotecas compartilhadas.

namespace.name.asan.search.paths

Uma lista de diretórios separada por dois-pontos para pesquisar bibliotecas compartilhadas quando o AddressSanitizer (ASan) está ativado.

namespace.name.search.paths é ignorado quando o ASan é ativado.

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

Isso indica que, quando a ASan está ativada, o vinculador dinâmico pesquisa /data/asan/system/${LIB} primeiro e depois pesquisa /system/${LIB}.

namespace.name.permitted.paths

Uma lista de diretórios separada por dois pontos (incluindo subdiretórios) em que o vinculador dinâmico pode carregar as bibliotecas compartilhadas (além de search.paths) quando isolated é true.

As bibliotecas compartilhadas que estão nos subdiretórios de permitted.paths também podem ser carregadas. Por exemplo, se permitted.paths for /system/${LIB}, /system/${LIB}/libc.so e /system/${LIB}/vndk/libutils.so poderão ser carregados.

Se isolated for false, permitted.paths serão ignorados e um aviso será emitido.

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

Isso indica que as bibliotecas compartilhadas em /system/${LIB}/hw podem ser carregadas no namespace default isolado.

Por exemplo, sem permitted.paths, libaudiohal.so não pode carregar /system/${LIB}/hw/audio.a2dp.default.so no namespace default.

namespace.name.asan.permitted.paths

Uma lista de diretórios separados por dois-pontos em que o vinculador dinâmico pode carregar as bibliotecas compartilhadas quando o ASan está ativado.

namespace.name.permitted.paths é ignorado quando o ASan está ativado.

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

Isso indica que, quando o ASan está ativado, as bibliotecas compartilhadas em /data/asan/system/${LIB}/hw ou /system/${LIB}/hw podem ser carregadas para o namespace default isolado.

namespace.name.visible

Um valor booleano que indica se o programa (diferente de libc) pode receber um identificador de namespace do vinculador com android_get_exported_namespace() e abrir uma biblioteca compartilhada no namespace do vinculador transmitindo o identificador para android_dlopen_ext().

Se visible for true, android_get_exported_namespace() sempre retornará o identificador se o namespace existir.

Se visible for false (padrão), android_get_exported_namespace() sempre retornará NULL, independentemente da presença do namespace. As bibliotecas compartilhadas só podem ser carregadas nesse namespace se (1) forem solicitadas por outro namespace de vinculador que tenha um link alternativo para esse namespace ou (2) forem solicitadas por outras bibliotecas compartilhadas ou executáveis nesse namespace.

namespace.sphal.visible = true

Isso indica que android_get_exported_namespace("sphal") pode retornar um identificador de namespace de vinculador válido.

Criação de namespace do vinculador

No Android 11, a configuração do vinculador é criada no momento da execução em /linkerconfig em vez de usar arquivos de texto simples em ${android-src}/system/core/rootdir/etc. A configuração é gerada no momento da inicialização com base no ambiente de execução, que inclui os seguintes itens:

  • Se o dispositivo oferece suporte ao VNDK
  • Versão do VNDK de destino da partição do fornecedor
  • Versão do VNDK da partição de produto
  • Módulos APEX instalados

A configuração do vinculador é criada ao resolver as dependências entre os namespaces dele. Por exemplo, se houver atualizações nos módulos APEX que incluem atualizações de dependência, a configuração do linker será gerada para refletir essas mudanças. Mais detalhes sobre como criar a configuração do linker podem ser encontrados em ${android-src}/system/linkerconfig.

Isolamento de namespace do vinculador

Há três tipos de configuração. Dependendo do valor de PRODUCT_TREBLE_LINKER_NAMESPACES e BOARD_VNDK_VERSION em BoardConfig.mk, a configuração correspondente será gerada no momento da inicialização.

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
Configuração selecionada Requisito de VTS
true current VNDK Obrigatório para dispositivos lançados com o Android 9 ou versões mais recentes
Vazio VNDK Lite Obrigatório para dispositivos lançados com o Android 8.x
false Vazio Legacy Para dispositivos não agudos

A configuração do VNDK Lite isola as bibliotecas compartilhadas SP-HAL e VNDK-SP. No Android 8.0, esse precisa ser o arquivo de configuração do vinculador dinâmico quando PRODUCT_TREBLE_LINKER_NAMESPACES for true.

A configuração do VNDK também isola as bibliotecas compartilhadas SP-HAL e VNDK-SP. Além disso, essa configuração fornece o isolamento completo do vinculador dinâmico. Ele garante que os módulos na partição do sistema não dependam das bibliotecas compartilhadas nas partições do fornecedor e vice-versa.

No Android 8.1 ou mais recente, a configuração do VNDK é a configuração padrão e é altamente recomendável ativar o isolamento completo do vinculador dinâmico definindo BOARD_VNDK_VERSION como current.

Configuração do VNDK

A configuração do VNDK isola as dependências da biblioteca compartilhada entre a partição do sistema e as do fornecedor. Em comparação com as configurações mencionadas na subseção anterior, as diferenças são descritas da seguinte maneira:

  • Processos de framework

    • Os namespaces default, vndk, sphal e rs são criados.
    • Todos os namespaces são isolados.
    • As bibliotecas compartilhadas do sistema são carregadas no namespace default.
    • As SP-HALs são carregadas no namespace sphal.
    • Bibliotecas compartilhadas do VNDK-SP carregadas no namespace vndk.
  • Processos do fornecedor

    • Os namespaces default, vndk e system são criados.
    • O namespace default está isolado.
    • As bibliotecas compartilhadas do fornecedor são carregadas no namespace default.
    • As bibliotecas compartilhadas do VNDK e do VNDK-SP são carregadas no namespace vndk.
    • O LL-NDK e as dependências dele são carregados no namespace system.

A relação entre os namespaces do vinculador é ilustrada abaixo.

Gráfico de namespace do vinculador descrito na configuração do VNDK

Figura 1. Isolamento de namespace do linker (configuração do VNDK).

Na imagem acima, LL-NDK e VNDK-SP representam as seguintes bibliotecas compartilhadas:

  • 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

Confira mais detalhes em /linkerconfig/ld.config.txt no dispositivo.

Configuração do VNDK Lite

A partir do Android 8.0, o vinculador dinâmico é configurado para isolar as bibliotecas compartilhadas SP-HAL e VNDK-SP para que os símbolos não entrem em conflito com outras bibliotecas compartilhadas do framework. A relação entre os namespaces do vinculador é mostrada abaixo.

Gráfico de namespace do vinculador descrito na configuração do VNDK Lite
Figura 2. Isolamento de namespace do vinculador (configuração do VNDK Lite)

LL-NDK e VNDK-SP são as seguintes bibliotecas compartilhadas:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libstdc++.so (não está na configuração)
    • libsync.so
    • libvndksupport.so
    • libz.so (movido para VNDK-SP na configuração)
  • 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

A tabela abaixo lista a configuração de namespaces para processos de framework, que foi extraído da seção [system] na configuração do VNDK Lite.

Namespace Propriedade 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 o 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 (link em inglês)

A tabela abaixo apresenta a configuração de namespaces para processos do fornecedor, que é extraída da seção [vendor] na configuração do VNDK Lite.

Namespace Propriedade 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} (descontinuado)
/product/${LIB} (descontinuado)
isolated false

Mais detalhes podem ser encontrados em /linkerconfig/ld.config.txt no dispositivo.

Histórico do documento

Mudanças no Android 11

  • No Android 11, os arquivos ld.config.*.txt estáticos são removidos da base de código, e o LinkerConfig os gera no momento de execução.

Mudanças no Android 9

  • No Android 9, o namespace do vinculador vndk foi adicionado aos processos do fornecedor, e as bibliotecas compartilhadas do VNDK são isoladas do namespace do vinculador padrão.
  • Substitua PRODUCT_FULL_TREBLE por um PRODUCT_TREBLE_LINKER_NAMESPACES mais específico.
  • O Android 9 muda os nomes dos seguintes arquivos de configuração do vinculador dinâmico.
    Android 8.x Android 9 Descrição
    ld.config.txt.in ld.config.txt Para dispositivos com isolamento de namespace do vinculador de execução
    ld.config.txt ld.config.vndk_lite.txt Para dispositivos com isolamento de namespace do vinculador VNDK-SP
    ld.config.legacy.txt ld.config.legacy.txt Para dispositivos legados com Android 7.x ou anterior
  • O android.hardware.graphics.allocator@2.0.so foi removido.
  • As partições product e odm foram adicionadas.