پلتفرم اندروید حاوی بسیاری از فایل های 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 استفاده میشوند استفاده کنید.
Build 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:
- فایل های لیست خالی ایجاد کنید.
- دستور
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