Mengimplementasikan Config File Schema API

Platform Android berisi banyak file XML untuk menyimpan data konfigurasi (misalnya, konfigurasi audio). Banyak file XML berada di partisi vendor, tetapi dibaca di partisi system. Dalam hal ini, skema file XML berfungsi sebagai antarmuka di kedua partisi, sehingga skema harus ditentukan secara eksplisit dan harus berkembang dengan cara yang kompatibel dengan versi sebelumnya.

Sebelum Android 10, platform ini tidak menyediakan mekanisme untuk mewajibkan penentuan dan penggunaan skema XML, atau untuk mencegah perubahan yang tidak kompatibel dalam skema. Android 10 menyediakan mekanisme ini, yang disebut Config File Schema API. Mekanisme ini terdiri dari alat yang disebut xsdc dan aturan build yang disebut xsd_config.

Alat xsdc adalah compiler Dokumen Skema XML (XSD). Alat ini mengurai file XSD yang menjelaskan skema file XML dan menghasilkan kode Java dan C++. Kode yang dihasilkan akan mengurai file XML yang sesuai dengan skema XSD menjadi hierarki objek, yang masing-masing memodelkan tag XML. Atribut XML dimodelkan sebagai kolom objek.

Aturan build xsd_config mengintegrasikan alat xsdc ke dalam sistem build. Untuk file input XSD tertentu, aturan build akan menghasilkan library Java dan C++. Anda dapat menautkan library ke modul tempat file XML yang sesuai dengan XSD dibaca dan digunakan. Anda dapat menggunakan aturan build untuk file XML Anda sendiri yang digunakan di seluruh partisi system dan vendor.

Build Config File Schema API

Bagian ini menjelaskan cara mem-build Config File Schema API.

Mengonfigurasi aturan build xsd_config di Android.bp

Aturan build xsd_config menghasilkan kode parser dengan alat xsdc. Properti package_name aturan build xsd_config menentukan nama paket kode Java yang dihasilkan.

Contoh aturan build xsd_config di Android.bp:

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

Contoh struktur direktori:

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

Sistem build menghasilkan daftar API menggunakan kode Java yang dihasilkan dan memeriksa API terhadapnya. Pemeriksaan API ini ditambahkan ke DroidCore dan dijalankan di m -j.

Membuat file daftar API

Pemeriksaan API memerlukan file daftar API dalam kode sumber.

File daftar API mencakup:

  • current.txt dan removed.txt memeriksa apakah API diubah dengan membandingkan dengan file API yang dihasilkan pada waktu build.
  • last_current.txt dan last_removed.txt memeriksa apakah API kompatibel dengan versi sebelumnya atau tidak dengan membandingkan file API.

Untuk membuat file daftar API:

  1. Membuat file daftar kosong.
  2. Jalankan perintah make update-api.

Menggunakan kode parser yang dihasilkan

Untuk menggunakan kode Java yang dihasilkan, tambahkan : sebagai awalan ke nama modul xsd_config di properti srcs Java. Paket kode Java yang dihasilkan sama dengan properti package_name.

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

Untuk menggunakan kode C++ yang dihasilkan, tambahkan nama modul xsd_config ke properti generated_sources dan generated_headers. Dan tambahkan libxml2 ke static_libs atau shared_libs, karena libxml2 diperlukan dalam kode parser yang dihasilkan. Namespace kode C++ yang dihasilkan sama dengan properti package_name. Misalnya, jika nama modul xsd_config adalah hal.manifest, namespace-nya adalah hal::manifest.

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

Menggunakan parser

Untuk menggunakan kode parser Java, gunakan metode XmlParser#read atau read{class-name} untuk menampilkan class elemen root. Penguraian terjadi pada saat ini.

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

Untuk menggunakan kode parser C++, sertakan file header terlebih dahulu. Nama file header adalah nama paket dengan titik (.) yang dikonversi menjadi garis bawah (_). Kemudian, gunakan metode read atau read{class-name} untuk menampilkan class elemen root. Penguraian terjadi pada saat ini. Nilai yang ditampilkan adalah 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();
        …
    }
    …
}

Semua API yang disediakan untuk menggunakan parser berada di api/current.txt. Untuk kesetaraan, semua nama elemen dan atribut dikonversi ke camel case (misalnya, ElementName) dan digunakan sebagai nama variabel, metode, dan class yang sesuai. Class elemen root yang diuraikan dapat diperoleh menggunakan fungsi read{class-name}. Jika hanya ada satu elemen root, nama fungsinya adalah read. Nilai subelemen atau atribut yang diuraikan dapat diperoleh menggunakan fungsi get{variable-name}.

Membuat kode parser

Pada umumnya, Anda tidak perlu menjalankan xsdc secara langsung. Sebagai gantinya, gunakan aturan build xsd_config, seperti yang dijelaskan dalam Mengonfigurasi aturan build xsd_config di Android.bp. Bagian ini menjelaskan antarmuka command line xsdc, hanya untuk kelengkapan. Hal ini mungkin berguna untuk proses debug.

Anda harus memberikan jalur ke file XSD dan paket ke alat xsdc. Paket adalah nama paket dalam kode Java dan namespace dalam kode C++. Opsi untuk menentukan apakah kode yang dihasilkan adalah Java atau C, masing-masing adalah -j atau -c. Opsi -o adalah jalur direktori output.

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

Contoh perintah:

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