Suporte ao sistema de compilação VNDK

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 módulos do fornecedor e instala automaticamente esses módulos em diretórios designados.

Exemplo de suporte de compilação 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 da estrutura e os módulos do fornecedor podem depender de libexample :

libexample vendor_available:true e vndk.enabled:true

Figura 1. Suporte VNDK ativado

Tanto o executável da estrutura /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 pelos módulos da estrutura e pelos módulos do fornecedor, duas variantes do libexample serão construídas. A variante principal (nomeada após libexample ) é usada pelos módulos da estrutura e a variante do fornecedor (nomeada após 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 do módulo .

Configurando o suporte de build

Para ativar 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 efeito global : Quando definida em BoardConfig.mk , todos os módulos são verificados. Como não há mecanismo para colocar um módulo incorreto na lista negra ou na lista branca, você deve limpar todas as dependências desnecessárias antes de adicionar BOARD_VNDK_VERSION . Você pode testar e compilar um módulo definindo BOARD_VNDK_VERSION em suas 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 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 depender dos cabeçalhos desses diretórios, você deverá especificar (explicitamente) as dependências com header_libs , static_libs e/ou shared_libs .

VNDK APEX

No Android 10 e versões anteriores, módulos com vndk.enabled foram instalados em /system/lib[64]/vndk[-sp]-${VER} . No Android 11 e versões posteriores, 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 nivelado e está disponível no caminho canônico /apex/com.android.vndk.v${VER} .

VNDK APEX

Figura 2. VNDK APEX

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ódulos, diversas propriedades de módulos relacionadas ao VNDK e verificações de dependência implementadas no sistema de compilação.

Módulos de fornecedor

Os módulos do fornecedor são executáveis ​​ou bibliotecas compartilhadas específicas do fornecedor que devem ser instalados 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 . Nos 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 permitirá dependências entre módulos de fornecedor e módulos de estrutura e emitirá erros se:

  • um módulo sem vendor:true depende de um módulo com vendor:true , ou
  • um módulo com vendor:true depende de um módulo não llndk_library que não possui vendor:true nem vendor_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

Bibliotecas compartilhadas LL-NDK são bibliotecas compartilhadas com ABIs estáveis. Os módulos da estrutura e do fornecedor compartilham a mesma implementação e a mais recente. Para cada biblioteca compartilhada LL-NDK, a 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 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 stub compartilhada para módulos do fornecedor, que se vincula a essas bibliotecas quando BOARD_VNDK_VERSION está habilitado. Um símbolo será incluído na biblioteca compartilhada stub somente se:

  • Não está definido no final da seção com _PRIVATE ou _PLATFORM ,
  • Não possui tag #platform-only e
  • Não possui tags #introduce* ou a tag corresponde ao destino.

VNDK

Nos arquivos Android.bp , as definições dos módulos cc_library , cc_library_static , cc_library_shared e cc_library_headers suportam 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 criadas. A variante principal deve ser tratada como um módulo de estrutura e a variante do fornecedor deve ser tratada como um módulo do fornecedor. Se alguns módulos da estrutura dependerem deste módulo, a variante principal será construída. Se alguns módulos do fornecedor dependerem deste módulo, a variante do fornecedor será construída. O sistema de compilação impõe as seguintes verificações de dependência:

  • A variante principal é sempre apenas de estrutura e inacessível aos módulos do fornecedor.
  • A variante do fornecedor está sempre inacessível aos módulos da estrutura.
  • Todas as dependências da variante do fornecedor, especificadas em header_libs , static_libs e/ou shared_libs , devem ser uma llndk_library ou um módulo com vendor_available ou vndk.enabled .
  • Se vendor_available for true , a variante do fornecedor estará acessível a todos os módulos do fornecedor.
  • Se vendor_available for false , a variante do fornecedor estará acessível apenas para outros módulos VNDK ou VNDK-SP (ou seja, módulos com vendor:true não podem vincular módulos vendor_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 for false , a variante do fornecedor será instalada em /vendor/lib[64] .
    • Se vndk.enabled for true , a variante do fornecedor será instalada no VNDK APEX ( com.android.vndk.v${VER} ).

A tabela abaixo resume como o sistema de compilação lida com as variantes do fornecedor:

fornecedor_disponível vndk
habilitado
vndk
suporte_same_process
Descrições das variantes do fornecedor
true false false As variantes do fornecedor são SOMENTE VND . Bibliotecas compartilhadas são instaladas em /vendor/lib[64] .
true Inválido (erro de compilação)
true false As variantes do fornecedor são VNDK . Bibliotecas compartilhadas são instaladas no VNDK APEX.
true As variantes do fornecedor são VNDK-SP . Bibliotecas compartilhadas são instaladas no VNDK APEX.

false

false

false

Nenhuma variante do fornecedor. Este módulo é SOMENTE FWK .

true Inválido (erro de compilação)
true false As variantes do fornecedor são VNDK-Private . 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 . 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.

Definição de extensões VNDK

No Android 9 e superior, Android.bp oferece suporte nativo a extensões VNDK. Para criar uma extensão VNDK, defina outro módulo com uma 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 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 base dos quais elas se estendem. Por exemplo, o binário de saída de libvndk_ext é libvndk.so em vez de libvndk_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 e vendor_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 limpa ao 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 os protetores 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 de ABI do VNDK compara a ABI das variantes do fornecedor do VNDK e das extensões do VNDK com os dumps de ABI de referência em prebuilts/abi-dumps/vndk .

  • Os símbolos exportados pelas variantes do fornecedor VNDK (por exemplo, /apex/com.android.vndk.v${VER}/lib[64]/libexample.so ) devem ser idênticos (não aos superconjuntos) dos símbolos definidos nos dumps ABI.
  • Os símbolos exportados pelas extensões VNDK (por exemplo, /vendor/lib[64]/vndk/libexample.so ) devem ser superconjuntos dos símbolos definidos nos dumps ABI.

Se as variantes ou extensões do fornecedor VNDK não atenderem aos 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 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, 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 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 VNDK libexample_ext :

  • Android.bp
  • include-ext/exemplo/ext/nome_do_recurso.h
  • include/exemplo/exemplo.h
  • src/exemplo.c
  • src/ext/feature_name.c

No seguinte Android.bp , as exportações libexample include apenas , enquanto as exportações libexample_ext include e include-ext . Isso garante que feature_name.h não será 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 viável separar extensões para arquivos de cabeçalho independentes, uma alternativa é adicionar proteções #ifdef . No entanto, certifique-se de que todos os usuários da extensão VNDK adicionem os sinalizadores de definição. Você pode definir cc_defaults para adicionar sinalizadores definidos a cflags e vincular bibliotecas compartilhadas com shared_libs .

Por exemplo, para adicionar uma nova função de membro Example2::get_b() à extensão VNDK libexample2_ext , você deve modificar o arquivo de cabeçalho existente e adicionar 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 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 receberão 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 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 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