Triển khai API giản đồ tệp cấu hình

Nền tảng Android chứa nhiều tệp XML để lưu trữ cấu hình (ví dụ: cấu hình âm thanh). Nhiều tệp XML nằm trong 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 và do đó giản đồ phải được chỉ định rõ ràng và phải phát triển theo khả năng tương thích ngược theo cách riêng.

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 lược đồ XML hoặc để ngăn chặ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à quy tắc bản 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++. Chiến lược phát hành đĩa đơn mã được tạo sẽ phân tích cú pháp các tệp XML phù hợp với giản đồ XSD thành một cây mà mỗi đối tượng trong số đó sẽ mô hình hoá một thẻ XML. Các thuộc tính XML được lập mô hình dưới dạng trường của các đố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 tệp đầu vào XSD nhất định, quy tắc bản dựng sẽ tạo các thư viện Java và C++. Bạn có thể liên kết thư viện với các mô-đun mà các tệp XML phù hợp với XSD được đọc và sử dụng. Bạn có thể sử dụng quy tắc bản dựng cho các tệp XML của riêng mình trên phân vùng systemvendor.

API giản đồ tệp cấu hình bản dựng

Phần này mô tả cách tạo API giản đồ tệp cấu hình.

Định cấu hình quy tắc bản dựng xsd_config trong Android.bp

Quy tắc bản dựng xsd_config tạo mã phân tích cú pháp bằng công cụ xsdc. Chiến lược phát hành đĩa đơn Thuộc tính package_name của quy tắc bản dựng xsd_config xác định tên gói của mã Java đã tạo.

Ví dụ về quy tắc bản 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 một danh sách API bằng mã Java đã tạo và các bước kiểm tra dựa vào nội dung đó. Bước kiểm tra API này được thêm vào DroidCore và được thực thi tại m -j.

Tạo tệp danh sách API

Các bước kiểm tra API yêu cầu API liệt kê các tệp trong mã nguồn.

API liệt kê các tệp bao gồm:

  • current.txtremoved.txt kiểm tra xem API có được thay đổi bằng so sánh với các tệp API đã tạo tại thời điểm xây dựng.
  • last_current.txtlast_removed.txt kiểm tra xem các API có đang tương thích ngược bằng cách so sánh với các tệp API.

Cách tạo tệp danh sách API:

  1. Tạo tệp danh sách trống.
  2. Chạy lệnh make update-api.

Sử dụng mã trình phân tích cú pháp đã tạo

Để sử dụng mã Java đã tạo, hãy thêm : làm tiền tố vào mô-đun xsd_config tên trong thuộc tính Java srcs. Gói mã Java đã tạo là giống như thuộc tính package_name.

java_library {
    name: "vintf_test_java",
    srcs: [
        "srcs/**/*.java"
        ":hal_manifest"
    ],
}

Để sử dụng mã C++ đã tạo, hãy thêm tên mô-đun xsd_config vào Thuộc tính generated_sourcesgenerated_headers. Và thêm libxml2 vào static_libs hoặc shared_libs, vì libxml2 là bắt buộc trong trình phân tích cú pháp đã tạo . Không gian tên của mã C++ đã tạo giống với thuộc tính package_name. Ví dụ: nếu tên mô-đun xsd_confighal.manifest, không gian tên 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ã phân tích cú pháp Java, hãy sử dụng XmlParser#read hoặc Phương thức read{class-name} để trả về lớp của thư mục 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 đó, 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à 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ả API được cung cấp để sử dụng trình phân tích cú pháp đều nằm trong api/current.txt. Để tính đồng nhất, tất cả tên phần tử và thuộc tính đều được chuyển đổi sang kiểu viết lạc đà (đối với ví dụ: ElementName) và được dùng làm biến, phương thức và biến tương ứng. tên lớp. Có thể lấy lớp của phần tử gốc đã phân tích cú pháp bằng cách sử dụng phương thức Hàm read{class-name}. Nếu chỉ có một gốc thì tên hàm là read. Giá trị của một phần tử con đã phân tích cú pháp hoặc có thể lấy thuộc tính get{variable-name} .

Tạo mã phân tích cú pháp

Trong hầu hết trường hợp, bạn không cần chạy xsdc trực tiếp. Sử dụng bản dựng xsd_config thay vào đó, như được mô tả trong Định cấu hình quy tắc bản dựng xsd_config trong Android.bp. Chiến dịch này phần này giải thích về giao diện dòng lệnh xsdc chỉ để cho đầy đủ thông tin. Chiến dịch này có thể hữu ích cho việc 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. Chiến lược phát hành đĩa đơn 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à -j hay -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 ví dụ:

$ xsdc audio_policy_configuration.xsd -p audio.policy -j