Config File Schema API लागू करना

Android प्लैटफ़ॉर्म में कॉन्फ़िगरेशन डेटा सेव करने के लिए कई एक्सएमएल फ़ाइलें होती हैं. उदाहरण के लिए, ऑडियो कॉन्फ़िगरेशन. ज़्यादातर एक्सएमएल फ़ाइलें vendor पार्टिशन में हैं, लेकिन उन्हें system पार्टिशन में पढ़ा जाता है. इस मामले में, एक्सएमएल फ़ाइल का स्कीमा, दोनों पार्टीशन के बीच इंटरफ़ेस के तौर पर काम करता है. इसलिए, स्कीमा को साफ़ तौर पर बताया जाना चाहिए. साथ ही, यह पिछले वर्शन के साथ काम करने वाला होना चाहिए.

Android 10 से पहले, प्लैटफ़ॉर्म में ऐसे तरीके उपलब्ध नहीं थे जिनसे एक्सएमएल स्कीमा को तय करने और इस्तेमाल करने की ज़रूरत हो या स्कीमा में ऐसे बदलावों को रोका जा सके जो काम नहीं करते. Android 10 में यह सुविधा उपलब्ध है. इसे कॉन्फ़िगरेशन फ़ाइल स्कीमा एपीआई कहा जाता है. इस तरीके में, xsdc नाम का एक टूल और xsd_config नाम का एक बिल्ड नियम शामिल होता है.

xsdc टूल, एक्सएमएल स्कीमा दस्तावेज़ (एक्सएसडी) कंपाइलर है. यह एक्सएमएल फ़ाइल के स्कीमा के बारे में बताने वाली XSD फ़ाइल को पार्स करता है. साथ ही, Java और C++ कोड जनरेट करता है. जनरेट किया गया कोड, XSD स्कीमा के मुताबिक एक्सएमएल फ़ाइलों को ऑब्जेक्ट के ट्री में पार्स करता है. इनमें से हर ऑब्जेक्ट, एक्सएमएल टैग को मॉडल करता है. एक्सएमएल एट्रिब्यूट को ऑब्जेक्ट के फ़ील्ड के तौर पर मॉडल किया जाता है.

xsd_config बिल्ड रूल, xsdc टूल को बिल्ड सिस्टम में इंटिग्रेट करता है. किसी XSD इनपुट फ़ाइल के लिए, बिल्ड रूल, Java और C++ लाइब्रेरी जनरेट करता है. लाइब्रेरी को उन मॉड्यूल से लिंक किया जा सकता है जहां XSD के मुताबिक एक्सएमएल फ़ाइलों को पढ़ा और इस्तेमाल किया जाता है. system और vendor, दोनों के लिए इस्तेमाल की गई अपनी एक्सएमएल फ़ाइलों के लिए, बिल्ड नियम का इस्तेमाल किया जा सकता है.

Build Config File Schema API

इस सेक्शन में, कॉन्फ़िगरेशन फ़ाइल स्कीमा एपीआई बनाने का तरीका बताया गया है.

Android.bp में xsd_config बिल्ड नियम को कॉन्फ़िगर करें

xsd_config बिल्ड रूल, xsdc टूल की मदद से पार्सर कोड जनरेट करता है. xsd_config बिल्ड रूल की package_name प्रॉपर्टी से, जनरेट किए गए Java कोड के पैकेज का नाम तय होता है.

Android.bp में xsd_config के लिए, बिल्ड नियम का उदाहरण:

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

बिल्ड सिस्टम, जनरेट किए गए Java कोड का इस्तेमाल करके एपीआई की सूची जनरेट करता है. साथ ही, एपीआई की जांच करता है. एपीआई की इस जांच को DroidCore में जोड़ा जाता है और इसे m -j पर लागू किया जाता है.

एपीआई की सूचियों वाली फ़ाइलें बनाना

एपीआई की जांच के लिए, सोर्स कोड में एपीआई की सूची वाली फ़ाइलें ज़रूरी होती हैं.

एपीआई से मिली फ़ाइलों की सूची में ये शामिल हैं:

  • current.txt और removed.txt, एपीआई में हुए बदलावों की जांच करते हैं. इसके लिए, वे बिल्ड टाइम पर जनरेट की गई एपीआई फ़ाइलों से तुलना करते हैं.
  • last_current.txt और last_removed.txt, एपीआई फ़ाइलों की तुलना करके यह देखते हैं कि एपीआई, पिछले वर्शन के साथ काम करते हैं या नहीं.

एपीआई की सूचियों वाले फ़ाइलें बनाने के लिए:

  1. खाली सूचियों वाली फ़ाइलें बनाएं.
  2. make update-api कमांड चलाएं.

जनरेट किए गए पार्सर कोड का इस्तेमाल करना

जनरेट किए गए Java कोड का इस्तेमाल करने के लिए, Java srcs प्रॉपर्टी में xsd_config मॉड्यूल के नाम से पहले : को प्रीफ़िक्स के तौर पर जोड़ें. जनरेट किए गए Java कोड का पैकेज, package_name प्रॉपर्टी के पैकेज के जैसा ही होता है.

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

जनरेट किए गए C++ कोड का इस्तेमाल करने के लिए, xsd_config और generated_headers प्रॉपर्टी में xsd_config मॉड्यूल का नाम जोड़ें.generated_sources साथ ही, 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 build rule का इस्तेमाल करें. इसके बारे में Android.bp में xsd_config बिल्ड रूल को कॉन्फ़िगर करना लेख में बताया गया है. इस सेक्शन में, xsdc कमांड लाइन इंटरफ़ेस के बारे में बताया गया है. यह डीबग करने के लिए काम आ सकता है.

आपको xsdc टूल को एक्सएसडी फ़ाइल का पाथ और एक पैकेज देना होगा. पैकेज, 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