پیاده‌سازی میانای برنامه‌سازی کاربردی طرح‌واره فایل پیکربندی

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

قبل‌از Android 10، پلاتفرم سازوکارهایی برای الزام به مشخص کردن و استفاده از طرح‌واره XML یا جلوگیری از تغییرات ناسازگار در طرح‌واره ارائه نمی‌کرد. ‫Android 10 این سازوکار را ارائه می‌دهد که «میانای برنامه‌سازی کاربردی طرحواره فایل پیکربندی» نامیده می‌شود. این سازوکار از ابزاری به‌نام xsdc و قانون ساختاری به‌نام xsd_config تشکیل شده است.

ابزار xsdc یک گردآورنده «سند طرحواره XML» (XSD) است. این ابزار فایل XSD را که طرح‌واره فایل XML را توصیف می‌کند تجزیه می‌کند و کد جاوا و C++ تولید می‌کند. کد تولیدشده فایل‌های XML را که با طرحواره XSD مطابقت دارند به درختی از اشیا تجزیه می‌کند که هریک از آن‌ها برچسب XML را مدل‌سازی می‌کند. مشخصه‌های XML به‌عنوان فیلدهای اشیا مدل‌سازی می‌شوند.

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

Build Config File Schema API

این بخش نحوه ساختن «میانای برنامه‌سازی کاربردی طرحواره فایل پیکربندی» را شرح می‌دهد.

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

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

نمونه قانون ساخت 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

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

ایجاد فایل‌های فهرست میانای برنامه‌سازی کاربردی

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

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

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

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

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

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

برای استفاده از کد Java تولیدشده، : را به‌عنوان پیشوند به نام ماژول xsd_config در دارایی Java srcs اضافه کنید. بسته کد Java تولیدشده با دارایی 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"],
}

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

برای استفاده از کد تجزیه‌کننده Java، از روش 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/current.txt است. برای یکپارچگی، همه نام‌های عنصر و مشخصه به نگارش شتری تبدیل می‌شوند (برای مثال، ElementName) و به‌عنوان متغیر، روش، و نام کلاس مربوطه استفاده می‌شوند. کلاس عنصر ریشه تجزیه‌شده را می‌توان بااستفاده از تابع read{class-name} به‌دست آورد. اگر فقط یک عنصر ریشه وجود داشته باشد، نام تابع read است. مقدار عنصر فرعی تجزیه‌شده یا مشخصه را می‌توان بااستفاده از تابع get{variable-name} به‌دست آورد.

تولید کد تجزیه‌کننده

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

باید مسیر فایل XSD و بسته‌ای را به ابزار xsdc بدهید. بسته نام بسته در کد Java و فضای نام در کد C++ است. گزینه‌های تعیین اینکه کد تولیدشده Java است یا 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