يحتوي نظام 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:
- إنشاء ملفات قوائم فارغة.
- قم بتشغيل الأمر
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