แพลตฟอร์ม Android มีไฟล์ XML จำนวนมากสำหรับจัดเก็บข้อมูลการกำหนดค่า (เช่น การกำหนดค่าเสียง) ไฟล์ XML จำนวนมากอยู่ในพาร์ติชัน vendor
แต่ไฟล์เหล่านั้นถูกอ่านในพาร์ติชัน system
ในกรณีนี้ สคีมาของไฟล์ XML ทำหน้าที่เป็นอินเทอร์เฟซระหว่างทั้งสองพาร์ติชัน ดังนั้นจึงต้องระบุสคีมาอย่างชัดเจนและต้องพัฒนาในลักษณะที่เข้ากันได้แบบย้อนหลัง
ก่อน Android 10 แพลตฟอร์มไม่มีกลไกที่ต้องระบุและใช้สคีมา XML หรือเพื่อป้องกันการเปลี่ยนแปลงที่เข้ากันไม่ได้ในสคีมา Android 10 มีกลไกนี้เรียกว่า Config File Schema API กลไกนี้ประกอบด้วยเครื่องมือชื่อ xsdc
และกฎการบิลด์ชื่อ xsd_config
เครื่องมือ xsdc
คือคอมไพเลอร์ XML Schema Document (XSD) แยกวิเคราะห์ไฟล์ XSD ที่อธิบายสคีมาของไฟล์ XML และสร้างโค้ด Java และ C++ โค้ดที่สร้างขึ้นจะแยกวิเคราะห์ไฟล์ XML ที่สอดคล้องกับสคีมา XSD ออกเป็นแผนผังของออบเจ็กต์ ซึ่งแต่ละไฟล์จะสร้างโมเดลแท็ก XML คุณลักษณะ XML ถูกสร้างแบบจำลองเป็นเขตข้อมูลของวัตถุ
กฎการสร้าง xsd_config
รวมเครื่องมือ xsdc
เข้ากับระบบการ build สำหรับไฟล์อินพุต XSD ที่กำหนด กฎการสร้างจะสร้างไลบรารี Java และ C++ คุณสามารถเชื่อมโยงไลบรารีกับโมดูลที่อ่านและใช้ไฟล์ XML ที่สอดคล้องกับ XSD คุณสามารถใช้กฎการสร้างสำหรับไฟล์ XML ของคุณเองที่ใช้ข้ามพาร์ติชัน system
และ vendor
การสร้าง Schema File Config API
ส่วนนี้จะอธิบายวิธีสร้าง Config File Schema API
การกำหนดค่ากฎการสร้าง xsd_config ใน Android.bp
กฎการสร้าง xsd_config
สร้างโค้ด parser ด้วยเครื่องมือ 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
ตรวจสอบว่า API มีการเปลี่ยนแปลงหรือไม่โดยเปรียบเทียบกับไฟล์ API ที่สร้างขึ้น ณ เวลาสร้าง -
last_current.txt
และlast_removed.txt
ตรวจสอบว่า API เข้ากันได้แบบย้อนหลังหรือไม่โดยเปรียบเทียบกับไฟล์ 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
ในโค้ด parser ที่สร้างขึ้น เนมสเปซของโค้ด 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 ทั้งหมดที่จัดเตรียมไว้เพื่อใช้ parser อยู่ใน 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