No Android 8.1 e superior, o sistema de compilação possui suporte VNDK integrado. Quando o suporte ao VNDK está habilitado, o sistema de compilação verifica as dependências entre os módulos, cria uma variante específica do fornecedor para os módulos do fornecedor e instala automaticamente esses módulos em diretórios designados.
Exemplo de suporte à compilação 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 do framework e os módulos do fornecedor podem depender de libexample
:
Tanto o executável do framework /system/bin/foo
quanto o executável do fornecedor /vendor/bin/bar
dependem de libexample
e possuem libexample
em suas propriedades shared_libs
.
Se libexample
for usado por módulos de estrutura e módulos de fornecedor, duas variantes de libexample
serão criadas. A variante principal (com o nome de libexample
) é usada pelos módulos de estrutura e a variante do fornecedor (com o nome de libexample.vendor
) é usada pelos 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 obter mais detalhes, consulte Definição de módulo .
Configurando o suporte de compilação
Para habilitar o suporte completo do sistema de compilação para um dispositivo de produto, adicione BOARD_VNDK_VERSION
a BoardConfig.mk
:
BOARD_VNDK_VERSION := current
Esta configuração tem um efeito global : Quando definido em BoardConfig.mk
, todos os módulos são verificados. Como não há mecanismo para colocar na lista negra ou na lista branca um módulo ofensivo, você deve limpar todas as dependências desnecessárias antes de adicionar BOARD_VNDK_VERSION
. Você pode testar e compilar um módulo configurando BOARD_VNDK_VERSION
em suas variáveis de ambiente:
$ BOARD_VNDK_VERSION=current m module_name.vendor
Quando BOARD_VNDK_VERSION
está habilitado, vários caminhos de pesquisa de cabeçalho global padrão são removidos . Esses incluem:
-
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 depende dos cabeçalhos desses diretórios, você deve especificar (explicitamente) as dependências com header_libs
, static_libs
e/ou shared_libs
.
VNDK APEX
No Android 10 e inferior, os módulos com vndk.enabled
foram instalados em /system/lib[64]/vndk[-sp]-${VER}
. No Android 11 e superior, 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 é nivelado ou não e está disponível no caminho canônico /apex/com.android.vndk.v${VER}
.
Definição do módulo
Para compilar o Android com BOARD_VNDK_VERSION
, você deve revisar 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 compilação.
Módulos de fornecedores
Os módulos do fornecedor são executáveis específicos do fornecedor ou bibliotecas compartilhadas que devem ser instaladas em uma partição do fornecedor. Nos arquivos Android.bp
, os módulos do fornecedor devem definir a propriedade vendor ou proprietária como true
. Em arquivos Android.mk
, os módulos do fornecedor devem definir LOCAL_VENDOR_MODULE
ou LOCAL_PROPRIETARY_MODULE
como true
.
Se BOARD_VNDK_VERSION
for definido, o sistema de compilação não permite dependências entre módulos de fornecedores e módulos de estrutura e emite 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ão-llndk_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 LL-NDK são bibliotecas compartilhadas com ABIs estáveis. Ambos os módulos da estrutura e do fornecedor compartilham a mesma implementação e a mais recente. Para cada biblioteca compartilhada LL-NDK, Android.bp
contém uma definição de módulo llndk_library
:
llndk_library { name: "libvndksupport", symbol_file: "libvndksupport.map.txt", }
Esta definição de módulo especifica um nome de módulo e um arquivo de símbolo que descreve os símbolos visíveis para os módulos do fornecedor. Por exemplo:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
Com base no arquivo de símbolos, o sistema de compilação gera uma biblioteca compartilhada de stub para módulos do fornecedor, que se vincula a essas bibliotecas quando BOARD_VNDK_VERSION
está ativado. Um símbolo é incluído na biblioteca compartilhada de stub somente se:
- Não está definido no final da seção com
_PRIVATE
ou_PLATFORM
, - Não tem a tag
#platform-only
e - Não possui tags
#introduce*
ou a tag corresponde ao destino.
VNDK
Em arquivos cc_library
, as definições de módulo Android.bp
, cc_library_static
, cc_library_shared
e cc_library_headers
compatíveis com 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 ) podem ser construídas. A variante principal deve ser tratada como um módulo de estrutura e a variante de fornecedor deve ser tratada como um módulo de fornecedor. Se alguns módulos de estrutura dependerem desse módulo, a variante principal será construída. Se alguns módulos do fornecedor dependerem desse módulo, a variante do fornecedor será criada. O sistema de compilação impõe as seguintes verificações de dependência:
- A variante principal é sempre somente estrutura e inacessível aos módulos do fornecedor.
- A variante do fornecedor é sempre inacessível aos módulos de estrutura.
- Todas as dependências da variante do fornecedor, que são especificadas em
header_libs
,static_libs
e/oushared_libs
, devem ser umallndk_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 de fornecedor será acessível apenas a 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 compilação lida com as variantes do fornecedor:
vendedor_disponível | vndk ativado | vndk suporte_mesmo_processo | Descrições de variantes de fornecedores |
---|---|---|---|
true | false | false | As variantes de fornecedor são VND-ONLY . As bibliotecas compartilhadas são instaladas em /vendor/lib[64] . |
true | Inválido (erro de compilação) | ||
true | false | As variantes de fornecedor são VNDK . As bibliotecas compartilhadas são instaladas no VNDK APEX. | |
true | As variantes de fornecedor são VNDK-SP . As bibliotecas compartilhadas são instaladas no VNDK APEX. | ||
| | | Nenhuma variante de fornecedor. Este módulo é FWK-ONLY . |
true | Inválido (erro de compilação) | ||
true | false | As variantes de fornecedor são VNDK-Private . As bibliotecas compartilhadas são instaladas no VNDK APEX. Eles não devem ser usados diretamente pelos 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 devem ser usados diretamente pelos módulos do fornecedor. |
Extensões VNDK
As extensões VNDK são bibliotecas compartilhadas VNDK com APIs adicionais. As extensões são instaladas em /vendor/lib[64]/vndk[-sp]
(sem sufixo de versão) e substituem as bibliotecas compartilhadas VNDK originais em tempo de execução.
Definindo extensões VNDK
No Android 9 e superior, Android.bp
oferece suporte nativo a extensões VNDK. Para construir uma extensão 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 as propriedades vendor:true
, vndk.enabled:true
e extends
define a extensão VNDK:
- A propriedade
extends
deve especificar um nome de biblioteca compartilhada VNDK base (ou nome de biblioteca compartilhada VNDK-SP). - As extensões VNDK (ou extensões VNDK-SP) são nomeadas de acordo com os nomes dos módulos básicos dos quais se estendem. Por exemplo, o binário de saída de
libvndk_ext
élibvndk.so
em vez delibvndk_ext.so
. - As extensões 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 básicas devem ter
vndk.enabled:true
evendor_available:true
.
Uma extensão VNDK-SP deve ser estendida de uma biblioteca compartilhada VNDK-SP ( vndk.support_system_process
deve 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 VNDK (ou extensões VNDK-SP) podem depender de bibliotecas compartilhadas de outros fornecedores:
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, }
Usando extensões VNDK
Se um módulo de fornecedor depender de APIs adicionais definidas por extensões VNDK, o módulo deverá especificar o nome da extensão VNDK em sua 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 de fornecedor depender de extensões VNDK, essas extensões VNDK serão instaladas em /vendor/lib[64]/vndk[-sp]
automaticamente. Se um módulo não depender mais de uma extensão VNDK, adicione uma etapa de limpeza a CleanSpec.mk
para remover a biblioteca compartilhada. Por exemplo:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Compilação condicional
Esta seção descreve 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 a seguir:
- 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 VNDK (por exemplo
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Sinalizadores de compilador condicional
O sistema de compilação do Android define __ANDROID_VNDK__
para variantes de fornecedores e extensões VNDK por padrão. Você pode proteger o código com as proteções 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
. Os cflags
ou cppflags
especificados em target.vendor
são específicos da variante do fornecedor.
Por exemplo, o seguinte Android.bp
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 compilação gera bibliotecas compartilhadas com os seguintes símbolos exportados:
Caminho de 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 sobre os símbolos exportados
O verificador VNDK ABI compara a ABI das variantes do fornecedor VNDK e as extensões VNDK com os dumps ABI de referência em prebuilts/abi-dumps/vndk
.
- Os símbolos exportados pelas variantes do fornecedor do VNDK (por exemplo
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) devem ser idênticos (não aos superconjuntos) aos símbolos definidos nos dumps da ABI. - Os símbolos exportados por extensões do VNDK (por exemplo
/vendor/lib[64]/vndk/libexample.so
) devem ser superconjuntos dos símbolos definidos nos dumps da ABI.
Se as variantes do fornecedor VNDK ou as extensões VNDK não seguirem os requisitos acima, o verificador VNDK ABI emitirá erros de compilação e interromperá a compilação.
Excluindo arquivos de origem ou bibliotecas compartilhadas de variantes de fornecedores
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 estejam vinculadas à variante do fornecedor, adicione essas bibliotecas à propriedade exclude_shared_libs
. Por 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 de 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, depende apenas da biblioteca compartilhada libboth
porque libfwk_only
é excluída pela propriedade exclude_shared_libs
.
Exportar cabeçalhos de extensões VNDK
Uma extensão VNDK pode adicionar novas classes ou novas funções a uma biblioteca compartilhada VNDK. Sugere-se manter essas declarações em cabeçalhos independentes e evitar alterar os cabeçalhos existentes.
Por exemplo, um novo arquivo de cabeçalho include-ext/example/ext/feature_name.h
é criado para a extensão libexample_ext
:
- Android.bp
- include-ext/example/ext/feature_name.h
- incluir/exemplo/exemplo.h
- src/exemplo.c
- src/ext/feature_name.c
No Android.bp a seguir, libexample
Android.bp
include
, enquanto as exportações de libexample_ext
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 extensões para arquivos de cabeçalho independentes, uma alternativa é adicionar #ifdef
guardas. No entanto, certifique-se de que todos os usuários de extensão VNDK adicionem os sinalizadores de definição. Você pode definir cc_defaults
para adicionar definir sinalizadores para cflags
e vincular bibliotecas compartilhadas com shared_libs
.
Por exemplo, para adicionar uma nova função de membro Example2::get_b()
à extensão libexample2_ext
, você deve modificar o arquivo de cabeçalho existente e adicionar um #ifdef
guard:
#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
em sua propriedade defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Pacotes de produtos
No sistema de compilação do Android, a variável PRODUCT_PACKAGES
especifica os executáveis, bibliotecas compartilhadas ou pacotes que devem 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 habilitado, módulos com vendor_available
ou vndk.enabled
recebem tratamento especial. Se um módulo de estrutura 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 de fornecedor depender de um módulo com vendor_available
, a variante de fornecedor será incluída no conjunto de instalação transitivo. No entanto, as variantes de módulos do fornecedor com vndk.enabled
são instaladas independentemente de serem usadas ou não pelos módulos do fornecedor.
Quando as dependências são invisíveis para o sistema de compilação (por exemplo, bibliotecas compartilhadas que podem ser abertas com dlopen()
em tempo de execução), você deve especificar 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 representa sua variante principal. Para especificar explicitamente a variante do fornecedor em PRODUCT_PACKAGES
, anexe um sufixo .vendor
ao nome do módulo. Por 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