Yapılandırma Dosyası Şeması API'sini uygulama

Android platformu, yapılandırma verilerini (ör. ses yapılandırması) depolamak için birçok XML dosyası içerir. XML dosyalarının çoğu vendor bölümünde olsa da system bölümünde okunuyor. Bu durumda, XML dosyasının şeması iki bölüm arasında arayüz olarak işlev görür. Bu nedenle, şema açıkça belirtilmeli ve geriye dönük uyumlu bir şekilde geliştirilmelidir.

Android 10'dan önce platform, XML şemasının belirtilmesini ve kullanılmasını zorunlu kılacak veya şemada uyumsuz değişiklikleri önleyecek mekanizmalar sağlamıyordu. Android 10, Yapılandırma Dosyası Şeması API'si adı verilen bu mekanizmayı sağlar. Bu mekanizma, xsdc adlı bir araç ve xsd_config adlı bir derleme kuralından oluşur.

xsdc aracı, XML Şema Belgesi (XSD) derleyicisidir. Bir XML dosyasının şemasını açıklayan bir XSD dosyasını ayrıştırır ve Java ile C++ kodu oluşturur. Oluşturulan kod, XSD şemasına uygun XML dosyalarını, her biri bir XML etiketini modelleyen bir nesne ağacına ayrıştırır. XML özellikleri, nesnelerin alanları olarak modellenir.

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

Build Config File Schema API

Bu bölümde, Yapılandırma Dosyası Şeması API'sinin nasıl oluşturulacağı açıklanmaktadır.

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

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 içinde örnek xsd_config derleme kuralı:

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 bu listeye göre kontrol eder. Bu API kontrolü DroidCore'a eklenir ve m -j tarihinde yürütülür.

API listeleri dosyaları oluşturma

API kontrolleri için kaynak kodda API listesi dosyaları gerekir.

API listesi dosyaları şunları içerir:

  • current.txt ve removed.txt, derleme zamanında oluşturulan API dosyalarıyla karşılaştırarak 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 listeleri 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 kullanma

Oluşturulan Java kodunu kullanmak için Java srcs özelliğindeki xsd_config modül adına : ön ekini 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. Ayrıca, oluşturulan ayrıştırıcı kodunda libxml2 gerekli olduğundan libxml2 öğesini static_libs veya shared_libs öğesine 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 bu sırada 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 (.) işaretleri alt çizgiye (_) dönüştürülmüş 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 bu sırada gerçekleşir. Döndürülen değer std::optional<>'dır.

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 için tüm öğe ve özellik adları camel case'e (ör. ElementName) dönüştürülür ve ilgili değişken, yöntem ve sınıf adı olarak kullanılır. Ayrıştırılan 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şturma

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

xsdc aracına XSD dosyasının yolunu ve bir paket vermeniz gerekir. Paket, Java kodunda paket adı, C++ kodunda ise ad alanıdır. Oluşturulan kodun Java mı yoksa C mi olduğunu belirlemek için sırasıyla -j veya -c seçeneklerini kullanabilirsiniz. -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