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

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

قبل از اندروید 10، این پلتفرم مکانیسم‌هایی برای نیاز به تعیین و استفاده از طرحواره XML یا جلوگیری از تغییرات ناسازگار در این طرح ارائه نمی‌کرد. اندروید 10 این مکانیزم را به نام 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 استفاده می‌شوند استفاده کنید.

Building Config File Schema 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 در ویژگی Java 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 استفاده کنید، همانطور که در پیکربندی قانون ساخت xsd_config در Android.bp توضیح داده شده است. این بخش رابط خط فرمان 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