پیاده سازی Config File Schema API

پلتفرم اندروید شامل فایل‌های XML زیادی برای ذخیره داده‌های پیکربندی (مثلاً پیکربندی صدا) است. بسیاری از فایل‌های XML در پارتیشن vendor قرار دارند، اما در پارتیشن system خوانده می‌شوند. در این حالت، طرحواره فایل XML به عنوان رابط بین دو پارتیشن عمل می‌کند و بنابراین طرحواره باید به صراحت مشخص شود و باید به شیوه‌ای سازگار با نسخه‌های قبلی تکامل یابد.

قبل از اندروید ۱۰، این پلتفرم مکانیسم‌هایی برای الزام به تعیین و استفاده از طرحواره XML یا جلوگیری از تغییرات ناسازگار در طرحواره ارائه نمی‌کرد. اندروید ۱۰ این مکانیسم را با نام Config File Schema API ارائه می‌دهد. این مکانیسم شامل ابزاری به نام xsdc و یک قانون ساخت به نام xsd_config است.

ابزار xsdc یک کامپایلر XML Schema Document (XSD) است. این کامپایلر، یک فایل XSD را که طرحواره یک فایل XML را توصیف می‌کند، تجزیه کرده و کد جاوا و ++C تولید می‌کند. کد تولید شده، فایل‌های XML را که با طرحواره XSD مطابقت دارند، به درختی از اشیاء تجزیه می‌کند که هر کدام یک برچسب XML را مدل‌سازی می‌کنند. ویژگی‌های XML به عنوان فیلدهای اشیاء مدل‌سازی می‌شوند.

قانون ساخت xsd_config ابزار xsdc را در سیستم ساخت ادغام می‌کند. برای یک فایل ورودی XSD مشخص، قانون ساخت، کتابخانه‌های جاوا و C++ را تولید می‌کند. می‌توانید کتابخانه‌ها را به ماژول‌هایی که فایل‌های XML مطابق با XSD در آنها خوانده و استفاده می‌شوند، پیوند دهید. می‌توانید از قانون ساخت برای فایل‌های XML خودتان که در سراسر system و پارتیشن‌های vendor استفاده می‌شوند، استفاده کنید.

ساخت API طرحواره فایل پیکربندی

این بخش نحوه ساخت API طرحواره فایل پیکربندی (Config File Schema API) را شرح می‌دهد.

پیکربندی قانون ساخت xsd_config در Android.bp

دستور ساخت xsd_config کد تجزیه‌گر را با ابزار xsdc تولید می‌کند. ویژگی package_name دستور ساخت xsd_config ، نام بسته کد جاوای تولید شده را تعیین می‌کند.

مثالی از دستور ساخت xsd_config در Android.bp :

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

ساختار دایرکتوری نمونه:

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

سیستم ساخت با استفاده از کد جاوای تولید شده، یک لیست API ایجاد می‌کند و API را با آن مقایسه می‌کند. این بررسی API به DroidCore اضافه شده و در m -j اجرا می‌شود.

ایجاد فایل‌های لیست API

بررسی‌های API نیاز به فهرست فایل‌های API در کد منبع دارد.

فایل‌های فهرست‌شده‌ی API شامل موارد زیر هستند:

  • current.txt و removed.txt با مقایسه با فایل‌های API تولید شده در زمان ساخت، بررسی می‌کنند که آیا APIها تغییر کرده‌اند یا خیر.
  • last_current.txt و last_removed.txt با مقایسه با فایل‌های API، بررسی می‌کنند که آیا APIها با نسخه‌های قبلی سازگار هستند یا خیر.

برای ایجاد لیست فایل‌ها در API:

  1. ایجاد فایل‌های لیست خالی.
  2. دستور make update-api را اجرا کنید.

از کد تجزیه‌گر تولید شده استفاده کنید

برای استفاده از کد جاوای تولید شده، علامت : را به عنوان پیشوند به نام ماژول xsd_config در ویژگی srcs جاوا اضافه کنید. بسته کد جاوای تولید شده همان ویژگی package_name است.

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

برای استفاده از کد C++ تولید شده، نام ماژول xsd_config را به ویژگی‌های generated_sources و generated_headers اضافه کنید. و libxml2 را به static_libs یا shared_libs اضافه کنید، زیرا libxml2 در کد تجزیه‌گر تولید شده مورد نیاز است. فضای نام کد C++ تولید شده همان ویژگی package_name است. برای مثال، اگر نام ماژول xsd_config hal.manifest باشد، فضای نام hal::manifest خواهد بود.

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

از تجزیه‌گر استفاده کنید

برای استفاده از کد تجزیه‌گر جاوا، از متد XmlParser#read یا read{ class-name } برای برگرداندن کلاس عنصر ریشه استفاده کنید. تجزیه در این زمان اتفاق می‌افتد.

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++، ابتدا فایل هدر را وارد کنید. نام فایل هدر، نام پکیج به همراه نقطه (.) است که به زیرخط (_) تبدیل شده است. سپس از متد read یا read{ class-name } برای برگرداندن کلاس عنصر ریشه استفاده کنید. تجزیه در این زمان اتفاق می‌افتد. مقدار برگشتی یک 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();
        
    }
    
}

تمام APIهای ارائه شده برای استفاده از تجزیه‌گر در api/current.txt قرار دارند. برای یکنواختی، نام تمام عناصر و ویژگی‌ها به صورت camel case (مثلاً ElementName ) تبدیل شده و به عنوان متغیر، متد و نام کلاس مربوطه استفاده می‌شوند. کلاس عنصر ریشه تجزیه شده را می‌توان با استفاده از تابع read{ class-name } بدست آورد. اگر فقط یک عنصر ریشه وجود داشته باشد، نام تابع read می‌شود. مقدار یک زیرعنصر یا ویژگی تجزیه شده را می‌توان با استفاده از تابع get{ variable-name } بدست آورد.

تولید کد تجزیه‌گر

در بیشتر موارد، نیازی به اجرای مستقیم xsdc ندارید. در عوض، همانطور که در «پیکربندی قانون ساخت xsd_config در Android.bp» توضیح داده شده است، از قانون ساخت xsd_config استفاده کنید. این بخش رابط خط فرمان xsdc را فقط برای تکمیل توضیح می‌دهد. این ممکن است برای اشکال‌زدایی مفید باشد.

شما باید مسیر فایل XSD و یک بسته را به ابزار xsdc بدهید. بسته در کد جاوا یک نام بسته و در کد ++C یک فضای نام است. گزینه‌هایی که تعیین می‌کنند کد تولید شده جاوا است یا C به ترتیب -j یا -c هستند. گزینه -o مسیر دایرکتوری خروجی است.

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

دستور مثال:

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