Wdrażanie interfejsu Config File Schema API

Platforma Androida zawiera wiele plików XML do przechowywania konfiguracji danych (np. konfiguracji audio). Wiele plików XML znajduje się w folderze vendor ale są odczytywane w partycji system. W tym przypadku schemat pliku XML służy jako interfejs między dwiema partycjami i dlatego schemat musi być wyraźnie określony i rozwijać się w sposób zgodny wstecznie; w dobrym stylu.

Przed Androidem 10 platforma nie udostępniała mechanizmów wymagających określenia schematu XML i użycia go do tego celu, niezgodne zmiany w schemacie. Android 10 zapewnia ten mechanizm nazywany interfejsem Config File Schema API. Mechanizm ten składa się z narzędzia, o nazwie xsdc i regułie kompilacji o nazwie xsd_config.

Narzędzie xsdc to kompilator XML Schema Document (XSD). Analizuje plik XSD opisuje schemat pliku XML i generuje kod w Javie i C++. wygenerowany kod analizuje pliki XML zgodne ze schematem XSD, tworząc drzewo obiektów, z których każdy modeluje tag XML. Atrybuty XML są modelowane jako pola kilka obiektów.

Reguła kompilacji xsd_config integruje narzędzie xsdc z systemem kompilacji. Dla danego pliku wejściowego XSD reguła kompilacji generuje biblioteki Java i C++. Ty może łączyć biblioteki z modułami, w których pliki XML zgodne z XSD są odczytywane i używane. Możesz użyć reguły kompilacji dla własnych plików XML w partycjach system i vendor.

Interfejs API schematu pliku konfiguracyjnego kompilacji

W tej sekcji opisujemy, jak utworzyć interfejs Config File Schema API.

Skonfiguruj regułę kompilacji xsd_config w Android.bp

Reguła kompilacji xsd_config generuje kod parsera za pomocą narzędzia xsdc. Właściwość package_name w regule kompilacji xsd_config określa nazwę pakietu w wygenerowanym kodzie Java.

Przykładowa reguła kompilacji xsd_config w Android.bp:

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

Przykładowa struktura katalogów:

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

System kompilacji generuje listę interfejsów API, korzystając z wygenerowanego kodu Java i sprawdza interfejs API. Ten test interfejsu API jest dodawany do DroidCore i wykonywany w m -j.

Tworzenie plików list interfejsów API

Kontrole interfejsu API wymagają, aby interfejsy API zawierały listę plików w kodzie źródłowym.

Lista plików w interfejsie API obejmuje:

  • current.txt i removed.txt sprawdzają, czy interfejsy API zostały zmienione przez porównując je z plikami wygenerowanymi przez interfejs API podczas kompilacji.
  • last_current.txt i last_removed.txt sprawdzają, czy interfejsy API są kompatybilności wstecznej przez porównanie z plikami interfejsu API.

Aby utworzyć listę plików interfejsu API:

  1. Utwórz pliki pustych list.
  2. Uruchom polecenie make update-api.

Użyj wygenerowanego kodu parsera

Aby użyć wygenerowanego kodu Java, dodaj do modułu xsd_config prefiks : we właściwości srcs środowiska Java. Pakiet wygenerowanego kodu Java jest taka sama jak właściwość package_name.

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

Aby użyć wygenerowanego kodu C++, dodaj nazwę modułu xsd_config do sekcji Usługi generated_sources i generated_headers. I dodaj libxml2 do static_libs lub shared_libs, ponieważ w wygenerowanym parserze wymagany jest parametr libxml2 w kodzie. Przestrzeń nazw wygenerowany kod w C++ jest taki sam jak właściwość package_name. Na przykład, jeśli nazwa modułu xsd_config to hal.manifest, przestrzeń nazw to hal::manifest

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

Użyj parsera

Aby skorzystać z kodu parsera Java, użyj instrukcji XmlParser#read lub Metoda read{class-name} zwracająca klasę pierwiastka . W tym momencie odbywa się analiza.

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();
            …
        }
    }
    …
}

Aby użyć kodu parsera C++, najpierw dołącz plik nagłówka. Nazwa plik nagłówka to nazwa pakietu z kropkami (.) przekonwertowanymi na podkreślenia (_). Następnie użyj metody read lub read{class-name}, aby zwrócić klasy elementu głównego. W tym momencie odbywa się analiza. Zwracana wartość to 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();
        …
    }
    …
}

Wszystkie interfejsy API udostępniane do korzystania z parsera mają język api/current.txt. Dla: jednorodność, nazwy wszystkich elementów i atrybutów są konwertowane na wielkość liter wielbłąda (na np. ElementName) i jest używany jako odpowiednia zmienna, metoda i nazwę zajęć. klasę przeanalizowanego elementu głównego można uzyskać za pomocą funkcji read{class-name}. Jeśli istnieje tylko jeden pierwiastek , nazwa funkcji to read. Wartość przeanalizowanego podelementu lub można uzyskać za pomocą funkcji get{variable-name} .

Wygeneruj kod parsera

W większości przypadków nie trzeba bezpośrednio uruchamiać xsdc. Użyj kompilacji xsd_config zgodnie z opisem w sekcji Konfigurowanie reguły kompilacji xsd_config w pliku Android.bp Ten wyjaśnia, jak działa interfejs wiersza poleceń xsdc. Ten może być przydatne podczas debugowania.

Musisz podać narzędziu xsdc ścieżkę do pliku XSD i pakietu. package to nazwa pakietu w kodzie Java i przestrzeń nazw w kodzie C++. Opcje aby określić, czy wygenerowany kod to Java czy C, to -j lub -c, . Opcja -o to ścieżka katalogu wyjściowego.

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

Przykładowe polecenie:

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