Implementar a API Config File Schema

A plataforma Android contém muitos arquivos XML para armazenar dados de configuração (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 build gera bibliotecas Java e C++. É possível vincular as bibliotecas aos módulos em que os arquivos XML que estão em conformidade com o XSD são lidos e usados. É possível 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 no 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. Essa verificação de API é adicionada ao DroidCore e executada em m -j.

Criar arquivos de listas de API

As verificações da API exigem que a API liste arquivos no código-fonte.

Os arquivos listados pela API incluem:

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

Para criar os arquivos de listas de API:

  1. Crie arquivos de listas vazios.
  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 é 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 adicione libxml2 a static_libs ou shared_libs, já que libxml2 é necessário no código do analisador gerado. O namespace do código C++ gerado é o mesmo da 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 método XmlParser#read ou read{class-name} para retornar a classe do elemento 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 do analisador C++, inclua primeiro o arquivo principal. O nome O 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 nesse 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 em letras maiúsculas e minúsculas (por exemplo, ElementName) e usados como a variável, o método e o nome da classe correspondentes. A classe do elemento raiz analisado pode ser obtida usando a 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, não é necessário executar xsdc diretamente. Use a regra de build xsd_config, conforme descrito em Como configurar a regra de build xsd_config no Android.bp. Esta seção explica a interface de linha de comando xsdc, apenas para fins de esclarecimento. Isso podem ser úteis para depuração.

Forneça à ferramenta xsdc o caminho para o arquivo XSD e um pacote. O pacote é um nome de pacote em código Java e um namespace em 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