Config File Schema API'yi Uygulama

Android platformu, yapılandırma verilerini (ör. ses yapılandırma) depolamak için birçok XML dosyası içerir. XML dosyalarının çoğu vendor bölümündedir ancak system bölümünde okunur. Bu durumda, XML dosyasının şeması iki bölüm için arayüz görevi görür. Dolayısıyla, şema açıkça belirtilmeli ve geriye dönük uyumlu bir şekilde gelişmelidir.

Android 10'dan önce platform, XML şemasının belirtilmesini ve kullanılmasını gerektiren veya şemadaki uyumsuz değişiklikleri önlemek için mekanizmalar sağlamıyordu. Android 10, Config File Schema API adlı bu mekanizmayı sağlar. Bu mekanizma, xsdc adlı bir araç ve xsd_config adlı bir derleme kuralından oluşur.

xsdc aracı, bir XML Şema Dokümanı (XSD) derleyicisidir. XML dosyasının şemasını açıklayan bir XSD dosyasını ayrıştırıp Java ve C++ kodu oluşturur. Oluşturulan kod, XSD şemasına uygun XML dosyalarını bir nesne ağacına ayrıştırır. Bu nesnelerin her biri, XML etiketi modeller. XML özellikleri, nesnelerin alanları olarak modellenir.

xsd_config derleme kuralı, xsdc aracını derleme sistemine entegre eder. Belirli bir XSD giriş dosyası için derleme kuralı, Java ve C++ kitaplıklarını oluşturur. Kitaplıkları, XSD'ye uygun XML dosyalarının okunduğu ve kullanıldığı modüllere bağlayabilirsiniz. Derleme kuralını, system ve vendor bölümlerinde kullanılan kendi XML dosyalarınız için kullanabilirsiniz.

Build Config File Schema API'si

Bu bölümde, Config File Schema API'nin nasıl oluşturulacağı açıklanmaktadır.

Android.bp'de xsd_config derleme kuralını yapılandırma

xsd_config derleme kuralı, ayrıştırıcı kodunu xsdc aracıyla oluşturur. xsd_config derleme kuralının package_name özelliği, oluşturulan Java kodunun paket adını belirler.

Android.bp konumunda xsd_config derleme kuralı örneği:

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

Örnek dizin yapısı:

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

Derleme sistemi, oluşturulan Java kodunu kullanarak bir API listesi oluşturur ve API'yi bununla karşılaştırarak kontrol eder. Bu API kontrolü, DroidCore'a eklendi ve m -j saatinde yürütüldü.

API listesi dosyaları oluşturun

API kontrolleri için API'nin kaynak kodundaki dosyaları listelemesi gerekir.

API listelerindeki dosyalar şunlardır:

  • current.txt ve removed.txt, derleme sırasında oluşturulan API dosyalarıyla karşılaştırma yaparak API'lerin değiştirilip değiştirilmediğini kontrol eder.
  • last_current.txt ve last_removed.txt, API dosyalarıyla karşılaştırarak API'lerin geriye dönük uyumlu olup olmadığını kontrol eder.

API listesi dosyalarını oluşturmak için:

  1. Boş liste dosyaları oluşturun.
  2. make update-api komutunu çalıştırın.

Oluşturulan ayrıştırıcı kodunu kullan

Oluşturulan Java kodunu kullanmak için Java srcs özelliğinde xsd_config modül adına ön ek olarak : kodunu ekleyin. Oluşturulan Java kodunun paketi package_name özelliğiyle aynıdır.

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

Oluşturulan C++ kodunu kullanmak için xsd_config modül adını generated_sources ve generated_headers özelliklerine ekleyin. Oluşturulan ayrıştırıcı kodunda libxml2 gerekli olduğundan static_libs veya shared_libs öğesine libxml2 ekleyin. Oluşturulan C++ kodunun ad alanı, package_name özelliğiyle aynıdır. Örneğin, xsd_config modülünün adı hal.manifest ise ad alanı hal::manifest olur.

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

Ayrıştırıcıyı kullanma

Java ayrıştırıcı kodunu kullanmak için kök öğenin sınıfını döndürmek üzere XmlParser#read veya read{class-name} yöntemini kullanın. Ayrıştırma şu anda gerçekleşir.

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

C++ ayrıştırıcı kodunu kullanmak için önce başlık dosyasını ekleyin. Başlık dosyasının adı, nokta (.) alt çizgiye (_) dönüştürülen paket adıdır. Ardından, kök öğenin sınıfını döndürmek için read veya read{class-name} yöntemini kullanın. Ayrıştırma şu anda gerçekleşir. Döndürülen değer ise std::optional<> olur.

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

Ayrıştırıcıyı kullanmak için sağlanan tüm API'ler api/current.txt içindedir. Tutarlılık sağlamak için tüm öğe ve özellik adları büyük/küçük harfe dönüştürülür (örneğin, ElementName) ve karşılık gelen değişken, yöntem ve sınıf adı olarak kullanılır. Ayrıştırılmış kök öğenin sınıfı, read{class-name} işlevi kullanılarak elde edilebilir. Yalnızca bir kök öğe varsa işlev adı read olur. Ayrıştırılmış bir alt öğenin veya özelliğin değeri, get{variable-name} işlevi kullanılarak elde edilebilir.

Ayrıştırıcı kodu oluştur

Çoğu durumda, xsdc öğesini doğrudan çalıştırmanız gerekmez. Bunun yerine, Android.bp'de xsd_config derleme kuralını yapılandırma bölümünde açıklandığı gibi xsd_config derleme kuralını kullanın. Bu bölümde, yalnızca eksiksiz olması için xsdc komut satırı arayüzü açıklanmaktadır. Bu işlem, hata ayıklama için faydalı olabilir.

xsdc aracına XSD dosyasının yolunu ve bir paketi vermeniz gerekir. Paket, Java kodundaki bir paket adı ve C++ kodunda bir ad alanıdır. Oluşturulan kodun Java mı yoksa C mi olduğunu belirleyen seçenekler sırasıyla -j veya -c. -o seçeneği, çıkış dizininin yoludur.

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

Örnek komut:

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