Implementar a API Config File Schema

A plataforma Android contém muitos arquivos XML para armazenar configurações (por exemplo, configuração de áudio). Muitos dos arquivos XML estão no arquivo vendor mas são lidas na partição system. Nesse caso, o esquema do arquivo XML serve como interface entre as duas partições. Assim, o esquema precisa ser especificado explicitamente e evoluir em um ambiente compatível com forma

Antes do Android 10, a plataforma não fornecia que exijam a especificação e o uso do esquema XML ou para evitar e alterações incompatíveis no esquema. O Android 10 oferece desse mecanismo, chamado API Config File Schema. Esse mecanismo consiste em uma ferramenta chamada xsdc e uma regra de build chamada xsd_config.

A ferramenta xsdc é um compilador de documento de esquema XML (XSD, na sigla em inglês). Ele analisa um arquivo XSD que descreve o esquema de um arquivo XML e gera código Java e C++. O o código gerado analisa arquivos XML que estão em conformidade com o esquema XSD em uma árvore de objetos, cada um modelando uma tag XML. Os atributos XML são modelados como campos dos objetos.

A regra de build xsd_config integra a ferramenta xsdc ao sistema de build. Para um determinado arquivo de entrada XSD, a regra de compilação gera bibliotecas Java e C++. Você pode vincular as bibliotecas aos módulos em que os arquivos XML estão em conformidade com o o XSD é lido e usado. Você pode usar a regra de build para seus próprios arquivos XML usados nas partições system e vendor.

API Build Config File Schema

Nesta seção, descrevemos como criar a API Config File Schema.

Configurar a regra de build xsd_config em Android.bp

A regra de build xsd_config gera o código do analisador com a ferramenta xsdc. O A propriedade package_name da regra de build xsd_config determina o nome do pacote o código Java gerado.

Exemplo de regra de build xsd_config em Android.bp:

xsd_config {
    name: "hal_manifest",
    srcs: ["hal_manifest.xsd"],
    package_name: "hal.manifest",
}

Exemplo de estrutura de diretórios:

├── Android.bp
├── api
│   ├── current.txt
│   ├── last_current.txt
│   ├── last_removed.txt
│   └── removed.txt
└── hal_manifest.xsd

O sistema de build gera uma lista de APIs usando o código Java gerado e verifica a API em relação a ele. Essa verificação de API é adicionada ao DroidCore e executada em m -j.

Criar arquivos de listas de APIs

As verificações de API exigem arquivos de listas da API no código-fonte.

Os arquivos de listas da API incluem:

  • current.txt e removed.txt verificam se as APIs são modificadas comparando com os arquivos de API gerados no tempo de build.
  • last_current.txt e last_removed.txt verificam se as APIs estão compatíveis com versões anteriores em comparação com os arquivos de API.

Para criar os arquivos de listas da API:

  1. Crie arquivos de listas vazias.
  2. Execute o comando make update-api.

Usar o código do analisador gerado

Para usar o código Java gerado, adicione : como um prefixo ao módulo xsd_config. na propriedade srcs do Java. O pacote do código Java gerado é o igual à propriedade package_name.

java_library {
    name: "vintf_test_java",
    srcs: [
        "srcs/**/*.java"
        ":hal_manifest"
    ],
}

Para usar o código em C++ gerado, adicione o nome do módulo xsd_config ao Propriedades generated_sources e generated_headers. E adicionar libxml2 a static_libs ou shared_libs, já que libxml2 é obrigatório no analisador gerado. o código-fonte é alterado. O namespace do elemento o código C++ gerado é o mesmo que a propriedade package_name. Por exemplo, se o nome do módulo xsd_config for hal.manifest, o namespace será hal::manifest

cc_library{
    name: "vintf_test_cpp",
    srcs: ["main.cpp"],
    generated_sources: ["hal_manifest"],
    generated_headers: ["hal_manifest"],
    shared_libs: ["libxml2"],
}

Usar o analisador

Para usar o código do analisador Java, use o XmlParser#read ou método read{class-name} para retornar a classe da raiz . A análise acontece no momento.

import hal.manifest.*;

…

class HalInfo {
    public String name;
    public String format;
    public String optional;
    …
}

void readHalManifestFromXml(File file) {
    …
    try (InputStream str = new BufferedInputStream(new FileInputStream(file))) {
        Manifest manifest = XmlParser.read(str);
        for (Hal hal : manifest.getHal()) {
            HalInfo halinfo;
            HalInfo.name = hal.getName();
            HalInfo.format = hal.getFormat();
            HalInfo.optional = hal.getOptional();
            …
        }
    }
    …
}

Para usar o código de analisador C++, inclua primeiro o arquivo principal. O nome arquivo principal é o nome do pacote com pontos (.) convertidos em sublinhados (_). Em seguida, use o método read ou read{class-name} para retornar a classe do elemento raiz. A análise acontece no momento. O valor de retorno é um std::optional<>.

include "hal_manifest.h"

…
using namespace hal::manifest

struct HalInfo {
    public std::string name;
    public std::string format;
    public std::string optional;
    …
};

void readHalManifestFromXml(std::string file_name) {
    …
    Manifest manifest = *read(file_name.c_str());
    for (Hal hal : manifest.getHal()) {
        struct HalInfo halinfo;
        HalInfo.name = hal.getName();
        HalInfo.format = hal.getFormat();
        HalInfo.optional = hal.getOptional();
        …
    }
    …
}

Todas as APIs fornecidas para usar o analisador estão em api/current.txt. Para uniformidade, todos os nomes de elementos e atributos são convertidos para camelCase (por exemplo, ElementName) e usada como a variável, o método e o nome da classe. A classe do elemento raiz analisado pode ser obtida usando-se o função read{class-name}. Se houver apenas uma raiz o nome da função será read. O valor de um subelemento analisado ou pode ser acessado usando o get{variable-name} função.

Gerar código do analisador

Na maioria dos casos, você não precisa executar xsdc diretamente. Usar o build xsd_config regra, conforme descrito nas Como configurar a regra de build xsd_config em Android.bp. Isso explica a interface de linha de comando xsdc, apenas para fins de integridade. Isso podem ser úteis para depuração.

Forneça à ferramenta xsdc o caminho para o arquivo XSD e um pacote. O package é um nome de pacote no código Java e um namespace no código C++. As opções para determinar se o código gerado é Java ou C são -j ou -c, respectivamente. A opção -o é o caminho do diretório de saída.

usage: xsdc path/to/xsd_file.xsd [-c] [-j] [-o <arg>] [-p]
 -c,--cpp           Generate C++ code.
 -j,--java          Generate Java code.
 -o,--outDir <arg>  Out Directory
 -p,--package       Package name of the generated java file. file name of
                    generated C++ file and header

Exemplo de comando:

$ xsdc audio_policy_configuration.xsd -p audio.policy -j