تنفيذ واجهة برمجة تطبيقات مخطط ملف الإعداد

يحتوي نظام Android الأساسي على العديد من ملفات XML لتخزين بيانات الضبط (مثل إعدادات الصوت). تقع العديد من ملفات XML في القسم vendor ، ولكن يتم قراءتها في القسم system. في هذه الحالة، يعمل مخطط ملف XML كواجهة على مستوى القسمين، وبالتالي يجب تحديد المخطط بشكل واضح ويجب تطويره بطريقة متوافقة مع الأنظمة القديمة.

قبل الإصدار 10 من Android، لم توفّر المنصة آليات لفرض تحديد مخطّط XML واستخدامه، أو لمنع إجراء تغييرات غير متوافقة في المخطّط. يقدّم نظام التشغيل Android 10 هذه الآلية التي تُعرف باسم Config File Schema API. تتألف هذه الآلية من أداة تُسمى xsdc وقاعدة إنشاء تُسمى xsd_config.

أداة xsdc هي أداة تجميع لمستند مخطّط XML ‏ (XSD). وهي تُحلِّل ملف XSD الذي يصف مخطّط ملف XML وتُنشئ رمز Java وC++. يُحلِّل الرمز المبرمَج المُنشئ ملفات XML المتوافقة مع مخطّط XSD إلى شجرة من العناصر، يمثّل كلّ منها علامة XML. يتم وضع سمات XML في حقول الكائنات.

تدمج قاعدة الإنشاء xsd_config أداة xsdc في نظام الإنشاء. بالنسبة إلى ملف إدخال XSD معيّن، تنشئ قاعدة الإنشاء مكتبتَي Java وC++. يمكنك ربط المكتبات بالوحدات التي يتم فيها قراءة ملفات XML المتوافقة مع schemaDTD واستخدامها. يمكنك استخدام قاعدة الإنشاء لملفات XML الخاصة بك المستخدَمة في قسمَي system وvendor.

واجهة برمجة تطبيقات مخطط ملف ضبط الإعدادات

يوضّح هذا القسم كيفية إنشاء واجهة برمجة التطبيقات 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 الذي تم إنشاؤه ويفحص واجهة برمجة التطبيقات مقابلها. تتم إضافة عملية التحقّق من واجهة برمجة التطبيقات هذه إلى DroidCore ويتم تنفيذها في m -j.

إنشاء ملفات قوائم واجهة برمجة التطبيقات

تتطلّب عمليات التحقّق من واجهة برمجة التطبيقات أن تُدرِج واجهة برمجة التطبيقات الملفات في رمز المصدر.

تشمل ملفات قوائم واجهة برمجة التطبيقات ما يلي:

  • يتحقّق current.txt وremoved.txt ممّا إذا تم تغيير واجهات برمجة التطبيقات من خلال مقارنة ملفات واجهات برمجة التطبيقات التي تم إنشاؤها في وقت التصميم.
  • يتحقق last_current.txt وlast_removed.txt مما إذا كانت واجهات برمجة التطبيقات متوافقة مع الأنظمة القديمة من خلال المقارنة بملفات واجهات برمجة التطبيقات.

لإنشاء قوائم واجهة برمجة التطبيقات للملفات:

  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. من أجل الاتساق، يتم تحويل جميع أسماء العناصر والسمات إلى كتابة الجمل بأسلوب CamelCase (على سبيل المثال،ElementName) واستخدامها كسمة المتغيّر والطريقة واسم الفئة المقابلَين. يمكن الحصول على فئة العنصر الجذري التحليلي باستخدام الدالة read{class-name}. إذا كان هناك عنصر جذر واحد فقط، يكون اسم الدالة هو read. يمكن الحصول على قيمة العنصر الفرعي أو السمة المحلّلة باستخدام الدالة get{variable-name}.

إنشاء رمز المُحلِّل

في معظم الحالات، ليس عليك تشغيل xsdc مباشرةً. استخدِم قاعدة الإنشاء xsd_config بدلاً من ذلك، كما هو موضّح في ضبط قاعدة الإنشاء xsd_config في Android.bp. يوضّح هذا القسم واجهة سطر الأوامر xsdc، وذلك من باب الكمال فقط. قد يكون هذا مفيدًا لتصحيح الأخطاء.

يجب منح أداة xsdc المسار إلى ملف XSD وحزمة. الحزمة عبارة عن اسم حزمة في كود 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