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

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

قبل Android 10، لم يوفر النظام الأساسي آليات لطلب تحديد مخطط 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 التي تتوافق مع XSD. يمكنك استخدام قاعدة الإنشاء لملفات XML الخاصة بك والمستخدمة عبر أقسام system vendor .

بناء 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

يقوم نظام البناء بإنشاء قائمة واجهة برمجة التطبيقات (API) باستخدام كود Java الذي تم إنشاؤه ويتحقق من واجهة برمجة التطبيقات (API) مقابلها. تتم إضافة فحص واجهة برمجة التطبيقات (API) هذا إلى DroidCore ويتم تنفيذه على m -j .

إنشاء ملفات قوائم API

تتطلب عمليات فحص واجهة برمجة التطبيقات (API) ملفات قوائم واجهة برمجة التطبيقات (API) في الكود المصدري.

تتضمن ملفات قوائم API ما يلي:

  • يتحقق current.txt و removed.txt مما إذا تم تغيير واجهات برمجة التطبيقات (APIs) من خلال مقارنتها بملفات API التي تم إنشاؤها في وقت الإنشاء.
  • يتحقق last_current.txt و last_removed.txt مما إذا كانت واجهات برمجة التطبيقات متوافقة مع الإصدارات السابقة من خلال مقارنتها بملفات API.

لإنشاء ملفات قوائم 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 ، فقط للاكتمال. قد يكون هذا مفيدًا لتصحيح الأخطاء.

يجب عليك إعطاء أداة 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