Nền tảng Android chứa nhiều tệp XML để lưu trữ dữ liệu cấu hình (ví dụ: cấu hình âm thanh). Nhiều tệp XML nằm trong phân vùng vendor, nhưng chúng được đọc trong phân vùng system. Trong trường hợp này, giản đồ của tệp XML đóng vai trò là giao diện trên hai phân vùng, do đó, giản đồ phải được chỉ định rõ ràng và phải phát triển theo cách tương thích ngược.
Trước Android 10, nền tảng này không cung cấp cơ chế để yêu cầu chỉ định và sử dụng giản đồ XML hoặc để ngăn các thay đổi không tương thích trong giản đồ. Android 10 cung cấp cơ chế này, được gọi là API giản đồ tệp cấu hình. Cơ chế này bao gồm một công cụ có tên là xsdc và một quy tắc xây dựng có tên là xsd_config.
Công cụ xsdc là trình biên dịch Tài liệu giản đồ XML (XSD). Công cụ này phân tích cú pháp tệp XSD mô tả giản đồ của tệp XML và tạo mã Java và C++. Mã được tạo sẽ phân tích cú pháp các tệp XML tuân theo giản đồ XSD thành một cây đối tượng, mỗi đối tượng mô hình hoá một thẻ XML. Các thuộc tính XML được mô hình hoá dưới dạng các trường của đối tượng.
Quy tắc xây dựng xsd_config tích hợp công cụ xsdc vào hệ thống xây dựng.
Đối với một tệp đầu vào XSD nhất định, quy tắc xây dựng sẽ tạo thư viện Java và C++. Bạn có thể liên kết các thư viện với các mô-đun nơi các tệp XML tuân theo XSD được đọc và sử dụng. Bạn có thể sử dụng quy tắc xây dựng cho các tệp XML của riêng mình được dùng trên các phân vùng system và vendor.
Xây dựng API giản đồ tệp cấu hình
Phần này mô tả cách xây dựng API giản đồ tệp cấu hình.
Định cấu hình quy tắc xây dựng xsd_config trong Android.bp
Quy tắc xây dựng xsd_config tạo mã trình phân tích cú pháp bằng công cụ xsdc. Thuộc tính package_name của quy tắc xây dựng xsd_config xác định tên gói của mã Java được tạo.
Ví dụ về quy tắc xây dựng xsd_config trong Android.bp:
xsd_config {
name: "hal_manifest",
srcs: ["hal_manifest.xsd"],
package_name: "hal.manifest",
}
Cấu trúc thư mục mẫu:
├── Android.bp
├── api
│ ├── current.txt
│ ├── last_current.txt
│ ├── last_removed.txt
│ └── removed.txt
└── hal_manifest.xsd
Hệ thống xây dựng tạo danh sách API bằng mã Java được tạo và kiểm tra API dựa trên danh sách đó. Quá trình kiểm tra API này được thêm vào DroidCore và thực thi tại m -j.
Tạo tệp danh sách API
Quá trình kiểm tra API yêu cầu tệp danh sách API trong mã nguồn.
Tệp danh sách API bao gồm:
current.txtvàremoved.txtkiểm tra xem các API có thay đổi hay không bằng cách so sánh với các tệp API được tạo tại thời điểm xây dựng.last_current.txtvàlast_removed.txtkiểm tra xem các API có tương thích ngược hay không bằng cách so sánh với các tệp API.
Cách tạo tệp danh sách API:
- Tạo tệp danh sách trống.
- Chạy lệnh
make update-api.
Sử dụng mã trình phân tích cú pháp được tạo
Để sử dụng mã Java được tạo, hãy thêm : làm tiền tố vào tên mô-đun xsd_config trong thuộc tính srcs của Java. Gói của mã Java được tạo giống với thuộc tính package_name.
java_library {
name: "vintf_test_java",
srcs: [
"srcs/**/*.java"
":hal_manifest"
],
}
Để sử dụng mã C++ được tạo, hãy thêm tên mô-đun xsd_config vào thuộc tính generated_sources và generated_headers. Và thêm libxml2 vào static_libs hoặc shared_libs, vì libxml2 là bắt buộc trong mã trình phân tích cú pháp được tạo. Không gian tên của mã C++ được tạo giống với thuộc tính package_name. Ví dụ: nếu tên mô-đun xsd_config là hal.manifest, thì không gian tên sẽ là hal::manifest.
cc_library{
name: "vintf_test_cpp",
srcs: ["main.cpp"],
generated_sources: ["hal_manifest"],
generated_headers: ["hal_manifest"],
shared_libs: ["libxml2"],
}
Sử dụng trình phân tích cú pháp
Để sử dụng mã trình phân tích cú pháp Java, hãy sử dụng phương thức XmlParser#read hoặc
read{class-name} để trả về lớp của phần tử gốc. Quá trình phân tích cú pháp diễn ra vào thời điểm này.
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();
…
}
}
…
}
Để sử dụng mã trình phân tích cú pháp C++, trước tiên, hãy thêm tệp tiêu đề. Tên của tệp tiêu đề là tên gói có dấu chấm (.) được chuyển đổi thành dấu gạch dưới (_).
Sau đó, hãy sử dụng phương thức read hoặc read{class-name} để trả về
lớp của phần tử gốc. Quá trình phân tích cú pháp diễn ra vào thời điểm này. Giá trị trả về là
a 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();
…
}
…
}
Tất cả các API được cung cấp để sử dụng trình phân tích cú pháp đều nằm trong api/current.txt. Để đảm bảo tính đồng nhất, tất cả tên phần tử và thuộc tính đều được chuyển đổi thành kiểu viết hoa Camel (ví dụ: ElementName) và được dùng làm tên biến, phương thức và lớp tương ứng. Bạn có thể lấy lớp của phần tử gốc được phân tích cú pháp bằng hàm
read{class-name}. Nếu chỉ có một phần tử gốc, thì tên hàm sẽ là read. Bạn có thể lấy giá trị của phần tử phụ hoặc
thuộc tính được phân tích cú pháp bằng hàm get{variable-name}.
Tạo mã trình phân tích cú pháp
Trong hầu hết các trường hợp, bạn không cần chạy xsdc trực tiếp. Thay vào đó, hãy sử dụng quy tắc xây dựng xsd_config, như mô tả trong phần
Định cấu hình quy tắc xây dựng xsd_config trong Android.bp. Phần này giải thích giao diện dòng lệnh xsdc, chỉ để hoàn thiện. Điều này có thể hữu ích khi gỡ lỗi.
Bạn phải cung cấp cho công cụ xsdc đường dẫn đến tệp XSD và một gói. Gói là tên gói trong mã Java và không gian tên trong mã C++. Các tuỳ chọn để xác định xem mã được tạo là Java hay C lần lượt là -j hoặc -c. Tuỳ chọn -o là đường dẫn của thư mục đầu ra.
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
Lệnh mẫu:
$ xsdc audio_policy_configuration.xsd -p audio.policy -j