No Android 8.1 e versões mais recentes, o sistema de build tem suporte integrado ao VNDK. Quando o suporte ao VNDK está ativado, o sistema de build verifica as dependências entre os módulos, cria uma variante específica do fornecedor para os módulos dele e instala automaticamente esses módulos em diretórios designados.
Exemplo de suporte para build do VNDK
Neste exemplo, a definição do módulo Android.bp
define uma biblioteca chamada libexample
. A propriedade vendor_available
indica que os módulos de framework e de fornecedor podem depender de
libexample
:
Figura 1.Suporte ativado.
Tanto o executável do framework /system/bin/foo
quanto o executável do fornecedor /vendor/bin/bar
dependem de libexample
e têm libexample
nas propriedades shared_libs
.
Se libexample
for usado por módulos de framework e de
fornecedor, duas variantes de libexample
serão criadas. A variante principal (nomeada após libexample
) é usada por módulos de framework, e a variante do fornecedor (nomeada após libexample.vendor
) é usada por módulos do fornecedor. As duas variantes são instaladas em diretórios diferentes:
- A variante principal é instalada em
/system/lib[64]/libexample.so
. - A variante do fornecedor é instalada no VNDK APEX porque
vndk.enabled
étrue
.
Para mais detalhes, consulte Definição de módulo.
Configurar o suporte a builds
Para ativar o suporte completo do sistema de build para um dispositivo de produto, adicione
BOARD_VNDK_VERSION
a BoardConfig.mk
:
BOARD_VNDK_VERSION := current
Essa configuração tem um efeito global: quando definida em BoardConfig.mk
, todos os módulos são verificados. Como não há um mecanismo para colocar um módulo ofensivo em uma lista de permissões ou de proibições, limpe todas as dependências desnecessárias antes de adicionar BOARD_VNDK_VERSION
. Você
pode testar e compilar um módulo definindo BOARD_VNDK_VERSION
nas
variáveis de ambiente:
$ BOARD_VNDK_VERSION=current m module_name.vendor
Quando BOARD_VNDK_VERSION
está ativado, vários caminhos de pesquisa de cabeçalho globais padrão são removidos. São eles:
frameworks/av/include
frameworks/native/include
frameworks/native/opengl/include
hardware/libhardware/include
hardware/libhardware_legacy/include
hardware/ril/include
libnativehelper/include
libnativehelper/include_deprecated
system/core/include
system/media/audio/include
Se um módulo depender dos cabeçalhos desses diretórios, especifique explicitamente as dependências com header_libs
, static_libs
e/ou shared_libs
.
APEX do VNDK
No Android 10 e em versões anteriores, os módulos com vndk.enabled
eram instalados em
/system/lib[64]/vndk[-sp]-${VER}
. No Android 11 e versões mais recentes,
as bibliotecas VNDK são empacotadas em um formato APEX, e o nome do VNDK APEX é
com.android.vndk.v${VER}
. Dependendo da configuração do dispositivo, o VNDK APEX é aplanado ou não aplanado e está disponível no caminho canônico /apex/com.android.vndk.v${VER}
.
Figura 2. APEX do VNDK.
Definição do módulo
Para criar o Android com BOARD_VNDK_VERSION
, revise a definição do módulo em Android.mk
ou Android.bp
. Esta seção descreve diferentes tipos de definições de módulo, várias propriedades de módulo relacionadas ao VNDK e verificações de dependência implementadas no sistema de build.
Módulos do fornecedor
Os módulos do fornecedor são executáveis ou bibliotecas compartilhadas específicos do fornecedor que
precisam ser instalados em uma partição do fornecedor. Em arquivos Android.bp
,
os módulos do fornecedor precisam definir a propriedade do fornecedor ou proprietária como true
.
Em arquivos Android.mk
, os módulos do fornecedor precisam definir
LOCAL_VENDOR_MODULE
ou LOCAL_PROPRIETARY_MODULE
como
true
.
Se BOARD_VNDK_VERSION
estiver definido, o sistema de build não permitirá
dependências entre módulos do fornecedor e módulos do framework e vai emitir erros se:
- um módulo sem
vendor:true
depende de um módulo comvendor:true
, ou - um módulo com
vendor:true
depende de um módulo nãollndk_library
que não temvendor:true
nemvendor_available:true
.
A verificação de dependência se aplica a header_libs
, static_libs
e shared_libs
em Android.bp
, e a LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
e LOCAL_SHARED_LIBRARIES
em Android.mk
.
LL-NDK
As bibliotecas compartilhadas do LL-NDK são bibliotecas compartilhadas com ABIs estáveis. Os módulos de framework e de fornecedor compartilham a mesma implementação mais recente. Para cada
biblioteca compartilhada LL-NDK, o cc_library
contém uma
propriedade llndk
com um arquivo de símbolos:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
O arquivo de símbolos descreve os símbolos visíveis para módulos do fornecedor. Exemplo:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
Com base no arquivo de símbolos, o sistema de build gera uma biblioteca compartilhada stub para
módulos do fornecedor, que são vinculados a essas bibliotecas quando
BOARD_VNDK_VERSION
está ativado. Um símbolo só é incluído na biblioteca compartilhada stub se:
- Não está definido no final da seção com
_PRIVATE
ou_PLATFORM
, - Não tem a tag
#platform-only
e - Não tem tags
#introduce*
ou a tag corresponde ao destino.
VNDK
Em arquivos Android.bp
, as definições de módulo cc_library
,
cc_library_static
, cc_library_shared
e
cc_library_headers
oferecem suporte a três propriedades
relacionadas ao VNDK: vendor_available
, vndk.enabled
e
vndk.support_system_process
.
Se vendor_available
ou vndk.enabled
for true
, duas variantes (core e vendor) poderão ser criadas. A variante principal precisa ser tratada como um módulo de framework, e a variante do fornecedor, como um módulo do fornecedor. Se alguns módulos de framework dependerem
dele, a variante principal será criada. Se alguns módulos do fornecedor
dependerem desse módulo, a variante do fornecedor será criada. O sistema de build aplica as seguintes verificações de dependência:
- A variante principal é sempre somente de framework e inacessível aos módulos do fornecedor.
- A variante do fornecedor está sempre inacessível aos módulos do framework.
- Todas as dependências da variante do fornecedor, especificadas em
header_libs
,static_libs
e/oushared_libs
, precisam ser umllndk_library
ou um módulo comvendor_available
ouvndk.enabled
. - Se
vendor_available
fortrue
, a variante do fornecedor estará acessível a todos os módulos do fornecedor. - Se
vendor_available
forfalse
, a variante do fornecedor só poderá ser acessada por outros módulos VNDK ou VNDK-SP (ou seja, módulos comvendor:true
não podem vincular módulosvendor_available:false
).
O caminho de instalação padrão para cc_library
ou
cc_library_shared
é determinado pelas seguintes regras:
- A variante principal é instalada em
/system/lib[64]
. - O caminho de instalação da variante do fornecedor pode variar:
- Se
vndk.enabled
forfalse
, a variante do fornecedor será instalada em/vendor/lib[64]
. - Se
vndk.enabled
fortrue
, a variante do fornecedor será instalada no VNDK APEX(com.android.vndk.v${VER}
).
- Se
A tabela abaixo resume como o sistema de build processa as variantes do fornecedor:
vendor_available | vndk enabled |
vndk support_system_process |
Descrições de variantes do fornecedor |
---|---|---|---|
true |
false |
false |
As variantes do fornecedor são VND-ONLY. As bibliotecas compartilhadas são
instaladas em /vendor/lib[64] . |
true |
Inválido (erro de build) | ||
true |
false |
As variantes do fornecedor são VNDK. As bibliotecas compartilhadas são instaladas no VNDK APEX. | |
true |
As variantes do fornecedor são VNDK-SP. As bibliotecas compartilhadas são instaladas no VNDK APEX. | ||
|
|
|
Sem variantes de fornecedor. Este módulo é FWK-ONLY. |
true |
Inválido (erro de build) | ||
true |
false |
As variantes do fornecedor são VNDK-Private. As bibliotecas compartilhadas são instaladas no VNDK APEX. Eles não podem ser usados diretamente por módulos do fornecedor. | |
true |
As variantes do fornecedor são VNDK-SP-Private. As bibliotecas compartilhadas são instaladas no VNDK APEX. Eles não podem ser usados diretamente por módulos do fornecedor. |
Extensões do VNDK
As extensões do VNDK são bibliotecas compartilhadas do VNDK com APIs adicionais. As extensões são
instaladas em /vendor/lib[64]/vndk[-sp]
(sem o sufixo de versão)
e substituem as bibliotecas compartilhadas do VNDK originais durante a execução.
Definir extensões do VNDK
No Android 9 e versões mais recentes, o Android.bp
oferece suporte nativo a extensões do VNDK. Para criar uma extensão do VNDK, defina outro módulo com um
vendor:true
e uma propriedade extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
Um módulo com propriedades vendor:true
, vndk.enabled:true
e
extends
define a extensão do VNDK:
- A propriedade
extends
precisa especificar um nome de biblioteca compartilhada VNDK de base (ou VNDK-SP). - As extensões do VNDK (ou VNDK-SP) recebem o nome dos módulos base
de que derivam. Por exemplo, o binário de saída de
libvndk_ext
élibvndk.so
em vez delibvndk_ext.so
. - As extensões do VNDK são instaladas em
/vendor/lib[64]/vndk
. - As extensões VNDK-SP são instaladas em
/vendor/lib[64]/vndk-sp
. - As bibliotecas compartilhadas de base precisam ter
vndk.enabled:true
evendor_available:true
.
Uma extensão VNDK-SP precisa ser estendida de uma biblioteca compartilhada VNDK-SP
(vndk.support_system_process
precisa ser igual):
cc_library { name: "libvndk_sp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, } cc_library { name: "libvndk_sp_ext", vendor: true, vndk: { enabled: true, extends: "libvndk_sp", support_system_process: true, }, }
As extensões do VNDK (ou VNDK-SP) podem depender de outras bibliotecas compartilhadas do fornecedor:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, shared_libs: [ "libvendor", ], } cc_library { name: "libvendor", vendor: true, }
Usar extensões do VNDK
Se um módulo do fornecedor depender de outras APIs definidas por extensões do VNDK, o
módulo precisará especificar o nome da extensão do VNDK na propriedade
shared_libs
:
// A vendor shared library example cc_library { name: "libvendor", vendor: true, shared_libs: [ "libvndk_ext", ], } // A vendor executable example cc_binary { name: "vendor-example", vendor: true, shared_libs: [ "libvndk_ext", ], }
Se um módulo do fornecedor depender de extensões do VNDK, elas serão
instaladas em /vendor/lib[64]/vndk[-sp]
automaticamente. Se um módulo não depender mais de uma extensão do VNDK, adicione uma etapa de limpeza a CleanSpec.mk
para remover a biblioteca compartilhada. Exemplo:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Compilação condicional
Nesta seção, descrevemos como lidar com as diferenças sutis (por exemplo, adicionar ou remover um recurso de uma das variantes) entre as três bibliotecas compartilhadas do VNDK:
- Variante principal (por exemplo,
/system/lib[64]/libexample.so
) - Variante do fornecedor (por exemplo,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - Extensão do VNDK (por exemplo,
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Flags condicionais do compilador
O sistema de build do Android define __ANDROID_VNDK__
para variantes do fornecedor e extensões do VNDK por padrão. Você pode proteger o código
com os mecanismos de proteção do pré-processador C:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
Além de __ANDROID_VNDK__
, diferentes cflags
ou cppflags
podem ser especificados em Android.bp
. O cflags
ou cppflags
especificado em target.vendor
é específico da variante do fornecedor.
Por exemplo, o Android.bp
a seguir define libexample
e libexample_ext
:
cc_library { name: "libexample", srcs: ["src/example.c"], vendor_available: true, vndk: { enabled: true, }, target: { vendor: { cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"], }, }, } cc_library { name: "libexample_ext", srcs: ["src/example.c"], vendor: true, vndk: { enabled: true, extends: "libexample", }, cflags: [ "-DLIBEXAMPLE_ENABLE_VNDK=1", "-DLIBEXAMPLE_ENABLE_VNDK_EXT=1", ], }
E esta é a listagem de código de src/example.c
:
void all() { } #if !defined(LIBEXAMPLE_ENABLE_VNDK) void framework_only() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK) void vndk() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK_EXT) void vndk_ext() { } #endif
De acordo com esses dois arquivos, o sistema de build gera bibliotecas compartilhadas com os seguintes símbolos exportados:
Caminho da instalação | Símbolos exportados |
---|---|
/system/lib[64]/libexample.so |
all , framework_only |
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so |
all , vndk |
/vendor/lib[64]/vndk/libexample.so |
all , vndk , vndk_ext |
Requisitos para os símbolos exportados
O verificador de ABI do VNDK
compara a ABI das variantes do fornecedor do VNDK e das
extensões do VNDK com os despejos de ABI de referência em
prebuilts/abi-dumps/vndk
.
- Os símbolos exportados por variantes do fornecedor VNDK (por exemplo,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) precisam ser idênticos aos símbolos definidos em despejos de ABI, e não superconjuntos deles. - Os símbolos exportados por extensões do VNDK (por exemplo,
/vendor/lib[64]/vndk/libexample.so
) precisam ser superconjuntos dos símbolos definidos em despejos de ABI.
Se as variantes do fornecedor do VNDK ou as extensões do VNDK não seguirem os requisitos acima, o verificador de ABI do VNDK vai emitir erros de build e interromper o build.
Excluir arquivos de origem ou bibliotecas compartilhadas de variantes do fornecedor
Para excluir arquivos de origem da variante do fornecedor, adicione-os à propriedade
exclude_srcs
. Da mesma forma, para garantir que as bibliotecas compartilhadas não sejam vinculadas à variante do fornecedor, adicione essas bibliotecas à propriedade exclude_shared_libs
. Exemplo:
cc_library { name: "libexample_cond_exclude", srcs: ["fwk.c", "both.c"], shared_libs: ["libfwk_only", "libboth"], vendor_available: true, target: { vendor: { exclude_srcs: ["fwk.c"], exclude_shared_libs: ["libfwk_only"], }, }, }
Neste exemplo, a variante principal de libexample_cond_exclude
inclui o código de fwk.c
e both.c
e depende
das bibliotecas compartilhadas libfwk_only
e libboth
. A variante do fornecedor de libexample_cond_exclude
inclui apenas o código de both.c
porque fwk.c
é excluído pela propriedade exclude_srcs
. Da mesma forma, ele depende apenas da biblioteca compartilhada
libboth
porque libfwk_only
é excluído pela propriedade
exclude_shared_libs
.
Exportar cabeçalhos de extensões VNDK
Uma extensão do VNDK pode adicionar novas classes ou funções a uma biblioteca compartilhada do VNDK. Recomendamos manter essas declarações em cabeçalhos independentes e evitar mudar os cabeçalhos atuais.
Por exemplo, um novo arquivo de cabeçalho
include-ext/example/ext/feature_name.h
é criado para a extensão
VNDK libexample_ext
:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
No Android.bp
a seguir, libexample
exporta apenas include
, enquanto libexample_ext
exporta include
e include-ext
. Isso garante que feature_name.h
não seja incluído incorretamente pelos usuários de libexample
:
cc_library { name: "libexample", srcs: ["src/example.c"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample_ext", srcs: [ "src/example.c", "src/ext/feature_name.c", ], export_include_dirs: [ "include", "include-ext", ], vendor: true, vndk: { enabled: true, extends: "libexample", }, }
Se não for possível separar as extensões em arquivos de cabeçalho independentes, uma alternativa é adicionar proteções #ifdef
. No entanto, verifique se todos os
usuários da extensão VNDK adicionam as flags de definição. Você pode definir cc_defaults
para adicionar flags de definição a cflags
e vincular bibliotecas compartilhadas com shared_libs
.
Por exemplo, para adicionar uma nova função de membro Example2::get_b()
à extensão do VNDK libexample2_ext
, modifique o arquivo de cabeçalho atual e adicione uma proteção #ifdef
:
#ifndef LIBEXAMPLE2_EXAMPLE_H_ #define LIBEXAMPLE2_EXAMPLE_H_ class Example2 { public: Example2(); void get_a(); #ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT void get_b(); #endif private: void *impl_; }; #endif // LIBEXAMPLE2_EXAMPLE_H_
Um cc_defaults
chamado libexample2_ext_defaults
é definido para os usuários de libexample2_ext
:
cc_library { name: "libexample2", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample2_ext", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor: true, vndk: { enabled: true, extends: "libexample2", }, cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], } cc_defaults { name: "libexample2_ext_defaults", shared_libs: [ "libexample2_ext", ], cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], }
Os usuários de libexample2_ext
podem simplesmente incluir
libexample2_ext_defaults
na propriedade defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Pacotes de produtos
No sistema de build do Android, a variável PRODUCT_PACKAGES
especifica os executáveis, as bibliotecas compartilhadas ou os pacotes que precisam ser
instalados no dispositivo. As dependências transitivas dos módulos especificados também são instaladas implicitamente no dispositivo.
Se BOARD_VNDK_VERSION
estiver ativado, os módulos com vendor_available
ou vndk.enabled
vão receber um tratamento especial. Se um módulo de framework depender de um módulo com
vendor_available
ou vndk.enabled
, a variante principal
será incluída no conjunto de instalação transitiva. Se um módulo do fornecedor
depender de um módulo com vendor_available
, a variante do fornecedor será
incluída no conjunto de instalação transitiva. No entanto, as variantes de fornecedores de módulos
com vndk.enabled
são instaladas, sejam ou não usadas por módulos de fornecedores.
Quando as dependências estão invisíveis para o sistema de build (por exemplo, bibliotecas compartilhadas
que podem ser abertas com dlopen()
em tempo de execução), especifique
os nomes dos módulos em PRODUCT_PACKAGES
para instalar esses módulos
explicitamente.
Se um módulo tiver vendor_available
ou vndk.enabled
,
o nome do módulo representará a variante principal. Para especificar explicitamente a variante do fornecedor em PRODUCT_PACKAGES
, anexe um sufixo .vendor
ao nome do módulo. Exemplo:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
Neste exemplo, libexample
significa
/system/lib[64]/libexample.so
e libexample.vendor
significa /vendor/lib[64]/libexample.so
. Para instalar
/vendor/lib[64]/libexample.so
, adicione libexample.vendor
a PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor