Home | History | Annotate | Download | only in libvintf
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // Convert objects from and to xml.
     18 
     19 #include <tinyxml2.h>
     20 
     21 #include "parse_string.h"
     22 #include "parse_xml.h"
     23 
     24 namespace android {
     25 namespace vintf {
     26 
     27 // --------------- tinyxml2 details
     28 
     29 using NodeType = tinyxml2::XMLElement;
     30 using DocType = tinyxml2::XMLDocument;
     31 
     32 // caller is responsible for deleteDocument() call
     33 inline DocType *createDocument() {
     34     return new tinyxml2::XMLDocument();
     35 }
     36 
     37 // caller is responsible for deleteDocument() call
     38 inline DocType *createDocument(const std::string &xml) {
     39     DocType *doc = new tinyxml2::XMLDocument();
     40     if (doc->Parse(xml.c_str()) == tinyxml2::XML_NO_ERROR) {
     41         return doc;
     42     }
     43     delete doc;
     44     return nullptr;
     45 }
     46 
     47 inline void deleteDocument(DocType *d) {
     48     delete d;
     49 }
     50 
     51 inline std::string printDocument(DocType *d) {
     52     tinyxml2::XMLPrinter p;
     53     d->Print(&p);
     54     return std::string{p.CStr()};
     55 }
     56 
     57 inline NodeType *createNode(const std::string &name, DocType *d) {
     58     return d->NewElement(name.c_str());
     59 }
     60 
     61 inline void appendChild(NodeType *parent, NodeType *child) {
     62     parent->InsertEndChild(child);
     63 }
     64 
     65 inline void appendChild(DocType *parent, NodeType *child) {
     66     parent->InsertEndChild(child);
     67 }
     68 
     69 inline void appendStrAttr(NodeType *e, const std::string &attrName, const std::string &attr) {
     70     e->SetAttribute(attrName.c_str(), attr.c_str());
     71 }
     72 
     73 // text -> text
     74 inline void appendText(NodeType *parent, const std::string &text, DocType *d) {
     75     parent->InsertEndChild(d->NewText(text.c_str()));
     76 }
     77 
     78 inline std::string nameOf(NodeType *root) {
     79     return root->Name() == NULL ? "" : root->Name();
     80 }
     81 
     82 inline std::string getText(NodeType *root) {
     83     return root->GetText() == NULL ? "" : root->GetText();
     84 }
     85 
     86 inline NodeType *getChild(NodeType *parent, const std::string &name) {
     87     return parent->FirstChildElement(name.c_str());
     88 }
     89 
     90 inline NodeType *getRootChild(DocType *parent) {
     91     return parent->FirstChildElement();
     92 }
     93 
     94 inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) {
     95     std::vector<NodeType *> v;
     96     for (NodeType *child = parent->FirstChildElement(name.c_str());
     97          child != nullptr;
     98          child = child->NextSiblingElement(name.c_str())) {
     99         v.push_back(child);
    100     }
    101     return v;
    102 }
    103 
    104 inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) {
    105     const char *c = root->Attribute(attrName.c_str());
    106     if (c == NULL)
    107         return false;
    108     *s = c;
    109     return true;
    110 }
    111 
    112 // --------------- tinyxml2 details end.
    113 
    114 // Helper functions for XmlConverter
    115 static bool parse(const std::string &attrText, bool *attr) {
    116     if (attrText == "true" || attrText == "1") {
    117         *attr = true;
    118         return true;
    119     }
    120     if (attrText == "false" || attrText == "0") {
    121         *attr = false;
    122         return true;
    123     }
    124     return false;
    125 }
    126 
    127 // ---------------------- XmlNodeConverter definitions
    128 
    129 template<typename Object>
    130 struct XmlNodeConverter : public XmlConverter<Object> {
    131     XmlNodeConverter() {}
    132     virtual ~XmlNodeConverter() {}
    133 
    134     // sub-types should implement these.
    135     virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0;
    136     virtual bool buildObject(Object *o, NodeType *n) const = 0;
    137     virtual std::string elementName() const = 0;
    138 
    139     // convenience methods for user
    140     inline const std::string &lastError() const { return mLastError; }
    141     inline NodeType *serialize(const Object &o, DocType *d) const {
    142         NodeType *root = createNode(this->elementName(), d);
    143         this->mutateNode(o, root, d);
    144         return root;
    145     }
    146     inline std::string serialize(const Object &o) const {
    147         DocType *doc = createDocument();
    148         appendChild(doc, serialize(o, doc));
    149         std::string s = printDocument(doc);
    150         deleteDocument(doc);
    151         return s;
    152     }
    153     inline bool deserialize(Object *object, NodeType *root) const {
    154         if (nameOf(root) != this->elementName()) {
    155             return false;
    156         }
    157         return this->buildObject(object, root);
    158     }
    159     inline bool deserialize(Object *o, const std::string &xml) const {
    160         DocType *doc = createDocument(xml);
    161         if (doc == nullptr) {
    162             this->mLastError = "Not a valid XML";
    163             return false;
    164         }
    165         bool ret = deserialize(o, getRootChild(doc));
    166         deleteDocument(doc);
    167         return ret;
    168     }
    169     inline NodeType *operator()(const Object &o, DocType *d) const {
    170         return serialize(o, d);
    171     }
    172     inline std::string operator()(const Object &o) const {
    173         return serialize(o);
    174     }
    175     inline bool operator()(Object *o, NodeType *node) const {
    176         return deserialize(o, node);
    177     }
    178     inline bool operator()(Object *o, const std::string &xml) const {
    179         return deserialize(o, xml);
    180     }
    181 
    182     // convenience methods for implementor.
    183 
    184     // All append* functions helps mutateNode() to serialize the object into XML.
    185     template <typename T>
    186     inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const {
    187         return appendStrAttr(e, attrName, ::android::vintf::to_string(attr));
    188     }
    189 
    190     inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const {
    191         return appendStrAttr(e, attrName, attr ? "true" : "false");
    192     }
    193 
    194     // text -> <name>text</name>
    195     inline void appendTextElement(NodeType *parent, const std::string &name,
    196                 const std::string &text, DocType *d) const {
    197         NodeType *c = createNode(name, d);
    198         appendText(c, text, d);
    199         appendChild(parent, c);
    200     }
    201 
    202     // text -> <name>text</name>
    203     template<typename Array>
    204     inline void appendTextElements(NodeType *parent, const std::string &name,
    205                 const Array &array, DocType *d) const {
    206         for (const std::string &text : array) {
    207             NodeType *c = createNode(name, d);
    208             appendText(c, text, d);
    209             appendChild(parent, c);
    210         }
    211     }
    212 
    213     template<typename T, typename Array>
    214     inline void appendChildren(NodeType *parent, const XmlNodeConverter<T> &conv,
    215             const Array &array, DocType *d) const {
    216         for (const T &t : array) {
    217             appendChild(parent, conv(t, d));
    218         }
    219     }
    220 
    221     // All parse* functions helps buildObject() to deserialize XML to the object. Returns
    222     // true if deserialization is successful, false if any error, and mLastError will be
    223     // set to error message.
    224     template <typename T>
    225     inline bool parseOptionalAttr(NodeType *root, const std::string &attrName,
    226             T &&defaultValue, T *attr) const {
    227         std::string attrText;
    228         bool success = getAttr(root, attrName, &attrText) &&
    229                        ::android::vintf::parse(attrText, attr);
    230         if (!success) {
    231             *attr = std::move(defaultValue);
    232         }
    233         return true;
    234     }
    235 
    236     template <typename T>
    237     inline bool parseAttr(NodeType *root, const std::string &attrName, T *attr) const {
    238         std::string attrText;
    239         bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
    240         if (!ret) {
    241             mLastError = "Could not find/parse attr with name \"" + attrName + "\" for element <"
    242                     + elementName() + ">";
    243         }
    244         return ret;
    245     }
    246 
    247     inline bool parseAttr(NodeType *root, const std::string &attrName, std::string *attr) const {
    248         bool ret = getAttr(root, attrName, attr);
    249         if (!ret) {
    250             mLastError = "Could not find attr with name \"" + attrName + "\" for element <"
    251                     + elementName() + ">";
    252         }
    253         return ret;
    254     }
    255 
    256     inline bool parseTextElement(NodeType *root,
    257             const std::string &elementName, std::string *s) const {
    258         NodeType *child = getChild(root, elementName);
    259         if (child == nullptr) {
    260             mLastError = "Could not find element with name <" + elementName + "> in element <"
    261                     + this->elementName() + ">";
    262             return false;
    263         }
    264         *s = getText(child);
    265         return true;
    266     }
    267 
    268     inline bool parseTextElements(NodeType *root, const std::string &elementName,
    269             std::vector<std::string> *v) const {
    270         auto nodes = getChildren(root, elementName);
    271         v->resize(nodes.size());
    272         for (size_t i = 0; i < nodes.size(); ++i) {
    273             v->at(i) = getText(nodes[i]);
    274         }
    275         return true;
    276     }
    277 
    278     template <typename T>
    279     inline bool parseChild(NodeType *root, const XmlNodeConverter<T> &conv, T *t) const {
    280         NodeType *child = getChild(root, conv.elementName());
    281         if (child == nullptr) {
    282             mLastError = "Could not find element with name <" + conv.elementName() + "> in element <"
    283                     + this->elementName() + ">";
    284             return false;
    285         }
    286         bool success = conv.deserialize(t, child);
    287         if (!success) {
    288             mLastError = conv.lastError();
    289         }
    290         return success;
    291     }
    292 
    293     template <typename T>
    294     inline bool parseOptionalChild(NodeType *root, const XmlNodeConverter<T> &conv,
    295             T &&defaultValue, T *t) const {
    296         NodeType *child = getChild(root, conv.elementName());
    297         if (child == nullptr) {
    298             *t = std::move(defaultValue);
    299             return true;
    300         }
    301         bool success = conv.deserialize(t, child);
    302         if (!success) {
    303             mLastError = conv.lastError();
    304         }
    305         return success;
    306     }
    307 
    308     template <typename T>
    309     inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::vector<T> *v) const {
    310         auto nodes = getChildren(root, conv.elementName());
    311         v->resize(nodes.size());
    312         for (size_t i = 0; i < nodes.size(); ++i) {
    313             if (!conv.deserialize(&v->at(i), nodes[i])) {
    314                 mLastError = "Could not parse element with name <" + conv.elementName()
    315                         + "> in element <" + this->elementName() + ">: " + conv.lastError();
    316                 return false;
    317             }
    318         }
    319         return true;
    320     }
    321 
    322     template <typename T>
    323     inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::set<T> *s) const {
    324         std::vector<T> vec;
    325         if (!parseChildren(root, conv, &vec)) {
    326             return false;
    327         }
    328         s->clear();
    329         s->insert(vec.begin(), vec.end());
    330         if (s->size() != vec.size()) {
    331             mLastError = "Duplicated elements <" + conv.elementName() + "> in element <"
    332                     + this->elementName() + ">";
    333             s->clear();
    334             return false;
    335         }
    336         return true;
    337     }
    338 
    339     inline bool parseText(NodeType *node, std::string *s) const {
    340         *s = getText(node);
    341         return true;
    342     }
    343 
    344     template <typename T>
    345     inline bool parseText(NodeType *node, T *s) const {
    346         std::string text = getText(node);
    347         bool ret = ::android::vintf::parse(text, s);
    348         if (!ret) {
    349             mLastError = "Could not parse text \"" + text + "\" in element <" + elementName() + ">";
    350         }
    351         return ret;
    352     }
    353 protected:
    354     mutable std::string mLastError;
    355 };
    356 
    357 template<typename Object>
    358 struct XmlTextConverter : public XmlNodeConverter<Object> {
    359     XmlTextConverter(const std::string &elementName)
    360         : mElementName(elementName) {}
    361 
    362     virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override {
    363         appendText(root, ::android::vintf::to_string(object), d);
    364     }
    365     virtual bool buildObject(Object *object, NodeType *root) const override {
    366         return this->parseText(root, object);
    367     }
    368     virtual std::string elementName() const { return mElementName; };
    369 private:
    370     std::string mElementName;
    371 };
    372 
    373 // ---------------------- XmlNodeConverter definitions end
    374 
    375 const XmlTextConverter<Version> versionConverter{"version"};
    376 
    377 const XmlTextConverter<VersionRange> versionRangeConverter{"version"};
    378 
    379 const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
    380 
    381 struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
    382     std::string elementName() const override { return "transport"; }
    383     void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override {
    384         if (object.arch != Arch::ARCH_EMPTY) {
    385             appendAttr(root, "arch", object.arch);
    386         }
    387         appendText(root, ::android::vintf::to_string(object.transport), d);
    388     }
    389     bool buildObject(TransportArch *object, NodeType *root) const override {
    390         if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch) ||
    391             !parseText(root, &object->transport)) {
    392             return false;
    393         }
    394         if (!object->isValid()) {
    395             this->mLastError = "transport == " + ::android::vintf::to_string(object->transport) +
    396                     " and arch == " + ::android::vintf::to_string(object->arch) +
    397                     " is not a valid combination.";
    398             return false;
    399         }
    400         return true;
    401     }
    402 };
    403 
    404 const TransportArchConverter transportArchConverter{};
    405 
    406 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
    407     std::string elementName() const override { return "value"; }
    408     void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override {
    409         appendAttr(root, "type", object.mType);
    410         appendText(root, ::android::vintf::to_string(object), d);
    411     }
    412     bool buildObject(KernelConfigTypedValue *object, NodeType *root) const override {
    413         std::string stringValue;
    414         if (!parseAttr(root, "type", &object->mType) ||
    415             !parseText(root, &stringValue)) {
    416             return false;
    417         }
    418         if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
    419             this->mLastError = "Could not parse kernel config value \"" + stringValue + "\"";
    420             return false;
    421         }
    422         return true;
    423     }
    424 };
    425 
    426 const KernelConfigTypedValueConverter kernelConfigTypedValueConverter{};
    427 
    428 struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
    429     std::string elementName() const override { return "config"; }
    430     void mutateNode(const KernelConfig &object, NodeType *root, DocType *d) const override {
    431         appendChild(root, kernelConfigKeyConverter(object.first, d));
    432         appendChild(root, kernelConfigTypedValueConverter(object.second, d));
    433     }
    434     bool buildObject(KernelConfig *object, NodeType *root) const override {
    435         if (   !parseChild(root, kernelConfigKeyConverter, &object->first)
    436             || !parseChild(root, kernelConfigTypedValueConverter, &object->second)) {
    437             return false;
    438         }
    439         return true;
    440     }
    441 };
    442 
    443 const KernelConfigConverter kernelConfigConverter{};
    444 
    445 struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
    446     std::string elementName() const override { return "interface"; }
    447     void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override {
    448         appendTextElement(root, "name", intf.name, d);
    449         appendTextElements(root, "instance", intf.instances, d);
    450     }
    451     bool buildObject(HalInterface *intf, NodeType *root) const override {
    452         std::vector<std::string> instances;
    453         if (!parseTextElement(root, "name", &intf->name) ||
    454             !parseTextElements(root, "instance", &instances)) {
    455             return false;
    456         }
    457         intf->instances.clear();
    458         intf->instances.insert(instances.begin(), instances.end());
    459         if (intf->instances.size() != instances.size()) {
    460             this->mLastError = "Duplicated instances in " + intf->name;
    461             return false;
    462         }
    463         return true;
    464     }
    465 };
    466 
    467 const HalInterfaceConverter halInterfaceConverter{};
    468 
    469 struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
    470     std::string elementName() const override { return "hal"; }
    471     void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override {
    472         appendAttr(root, "format", hal.format);
    473         appendAttr(root, "optional", hal.optional);
    474         appendTextElement(root, "name", hal.name, d);
    475         appendChildren(root, versionRangeConverter, hal.versionRanges, d);
    476         appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d);
    477     }
    478     bool buildObject(MatrixHal *object, NodeType *root) const override {
    479         std::vector<HalInterface> interfaces;
    480         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) ||
    481             !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional) ||
    482             !parseTextElement(root, "name", &object->name) ||
    483             !parseChildren(root, versionRangeConverter, &object->versionRanges) ||
    484             !parseChildren(root, halInterfaceConverter, &interfaces)) {
    485             return false;
    486         }
    487         for (auto&& interface : interfaces) {
    488             std::string name{interface.name};
    489             auto res = object->interfaces.emplace(std::move(name), std::move(interface));
    490             if (!res.second) {
    491                 this->mLastError = "Duplicated instance entry " + res.first->first;
    492                 return false;
    493             }
    494         }
    495         return true;
    496     }
    497 };
    498 
    499 const MatrixHalConverter matrixHalConverter{};
    500 
    501 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
    502     std::string elementName() const override { return "kernel"; }
    503     void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override {
    504         appendAttr(root, "version", kernel.mMinLts);
    505         appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
    506     }
    507     bool buildObject(MatrixKernel *object, NodeType *root) const override {
    508         if (!parseAttr(root, "version", &object->mMinLts) ||
    509             !parseChildren(root, kernelConfigConverter, &object->mConfigs)) {
    510             return false;
    511         }
    512         return true;
    513     }
    514 };
    515 
    516 const MatrixKernelConverter matrixKernelConverter{};
    517 
    518 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
    519     std::string elementName() const override { return "hal"; }
    520     void mutateNode(const ManifestHal &hal, NodeType *root, DocType *d) const override {
    521         appendAttr(root, "format", hal.format);
    522         appendTextElement(root, "name", hal.name, d);
    523         if (!hal.transportArch.empty()) {
    524             appendChild(root, transportArchConverter(hal.transportArch, d));
    525         }
    526         appendChildren(root, versionConverter, hal.versions, d);
    527         appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d);
    528     }
    529     bool buildObject(ManifestHal *object, NodeType *root) const override {
    530         std::vector<HalInterface> interfaces;
    531         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) ||
    532             !parseTextElement(root, "name", &object->name) ||
    533             !parseChild(root, transportArchConverter, &object->transportArch) ||
    534             !parseChildren(root, versionConverter, &object->versions) ||
    535             !parseChildren(root, halInterfaceConverter, &interfaces)) {
    536             return false;
    537         }
    538         object->interfaces.clear();
    539         for (auto &&interface : interfaces) {
    540             auto res = object->interfaces.emplace(interface.name,
    541                                                   std::move(interface));
    542             if (!res.second) {
    543                 this->mLastError = "Duplicated instance entry " + res.first->first;
    544                 return false;
    545             }
    546         }
    547         if (!object->isValid()) {
    548             this->mLastError = "'" + object->name + "' is not a valid Manifest HAL.";
    549             return false;
    550         }
    551         return true;
    552     }
    553 };
    554 
    555 // Convert ManifestHal from and to XML. Returned object is guaranteed to have
    556 // .isValid() == true.
    557 const ManifestHalConverter manifestHalConverter{};
    558 
    559 const XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"};
    560 const XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"};
    561 
    562 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
    563     std::string elementName() const override { return "sepolicy"; }
    564     void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override {
    565         appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d));
    566         appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d);
    567     }
    568     bool buildObject(Sepolicy *object, NodeType *root) const override {
    569         if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion) ||
    570             !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges)) {
    571             return false;
    572         }
    573         return true;
    574     }
    575 };
    576 const SepolicyConverter sepolicyConverter{};
    577 
    578 const XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"};
    579 const XmlTextConverter<std::string> vndkLibraryConverter{"library"};
    580 
    581 struct VndkConverter : public XmlNodeConverter<Vndk> {
    582     std::string elementName() const override { return "vndk"; }
    583     void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override {
    584         appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d));
    585         appendChildren(root, vndkLibraryConverter, object.mLibraries, d);
    586     }
    587     bool buildObject(Vndk *object, NodeType *root) const override {
    588         if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange) ||
    589             !parseChildren(root, vndkLibraryConverter, &object->mLibraries)) {
    590             return false;
    591         }
    592         return true;
    593     }
    594 };
    595 
    596 const VndkConverter vndkConverter{};
    597 
    598 struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
    599     std::string elementName() const override { return "sepolicy"; }
    600     void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
    601         appendChild(root, versionConverter(m, d));
    602     }
    603     bool buildObject(Version *object, NodeType *root) const override {
    604         return parseChild(root, versionConverter, object);
    605     }
    606 };
    607 const HalManifestSepolicyConverter halManifestSepolicyConverter{};
    608 
    609 struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
    610     std::string elementName() const override { return "manifest"; }
    611     void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override {
    612         appendAttr(root, "version", HalManifest::kVersion);
    613         appendAttr(root, "type", m.mType);
    614         appendChildren(root, manifestHalConverter, m.getHals(), d);
    615         if (m.mType == SchemaType::DEVICE) {
    616             appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
    617         } else if (m.mType == SchemaType::FRAMEWORK) {
    618             appendChildren(root, vndkConverter, m.framework.mVndks, d);
    619         }
    620     }
    621     bool buildObject(HalManifest *object, NodeType *root) const override {
    622         Version version;
    623         std::vector<ManifestHal> hals;
    624         if (!parseAttr(root, "version", &version) ||
    625             !parseAttr(root, "type", &object->mType) ||
    626             !parseChildren(root, manifestHalConverter, &hals)) {
    627             return false;
    628         }
    629         if (version != HalManifest::kVersion) {
    630             this->mLastError = "Unrecognized manifest.version";
    631             return false;
    632         }
    633         if (object->mType == SchemaType::DEVICE) {
    634             // tags for device hal manifest only.
    635             // <sepolicy> can be missing because it can be determined at build time, not hard-coded
    636             // in the XML file.
    637             if (!parseOptionalChild(root, halManifestSepolicyConverter, {},
    638                     &object->device.mSepolicyVersion)) {
    639                 return false;
    640             }
    641         } else if (object->mType == SchemaType::FRAMEWORK) {
    642             if (!parseChildren(root, vndkConverter, &object->framework.mVndks)) {
    643                 return false;
    644             }
    645             for (const auto &vndk : object->framework.mVndks) {
    646                 if (!vndk.mVersionRange.isSingleVersion()) {
    647                     this->mLastError = "vndk.version " + to_string(vndk.mVersionRange)
    648                             + " cannot be a range for manifests";
    649                     return false;
    650                 }
    651             }
    652         }
    653         for (auto &&hal : hals) {
    654             std::string description{hal.name};
    655             if (!object->add(std::move(hal))) {
    656                 this->mLastError = "Duplicated manifest.hal entry " + description;
    657                 return false;
    658             }
    659         }
    660         return true;
    661     }
    662 };
    663 
    664 const HalManifestConverter halManifestConverter{};
    665 
    666 const XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"};
    667 struct AvbConverter : public XmlNodeConverter<Version> {
    668     std::string elementName() const override { return "avb"; }
    669     void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
    670         appendChild(root, avbVersionConverter(m, d));
    671     }
    672     bool buildObject(Version *object, NodeType *root) const override {
    673         return parseChild(root, avbVersionConverter, object);
    674     }
    675 };
    676 const AvbConverter avbConverter{};
    677 
    678 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
    679     std::string elementName() const override { return "compatibility-matrix"; }
    680     void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override {
    681         appendAttr(root, "version", CompatibilityMatrix::kVersion);
    682         appendAttr(root, "type", m.mType);
    683         appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d);
    684         if (m.mType == SchemaType::FRAMEWORK) {
    685             appendChildren(root, matrixKernelConverter, m.framework.mKernels, d);
    686             appendChild(root, sepolicyConverter(m.framework.mSepolicy, d));
    687             appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d));
    688         } else if (m.mType == SchemaType::DEVICE) {
    689             appendChild(root, vndkConverter(m.device.mVndk, d));
    690         }
    691     }
    692     bool buildObject(CompatibilityMatrix *object, NodeType *root) const override {
    693         Version version;
    694         std::vector<MatrixHal> hals;
    695         if (!parseAttr(root, "version", &version) ||
    696             !parseAttr(root, "type", &object->mType) ||
    697             !parseChildren(root, matrixHalConverter, &hals)) {
    698             return false;
    699         }
    700 
    701         if (object->mType == SchemaType::FRAMEWORK) {
    702             // <avb> and <sepolicy> can be missing because it can be determined at build time, not
    703             // hard-coded in the XML file.
    704             if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels) ||
    705                 !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy) ||
    706                 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion)) {
    707                 return false;
    708             }
    709         } else if (object->mType == SchemaType::DEVICE) {
    710             // <vndk> can be missing because it can be determined at build time, not hard-coded
    711             // in the XML file.
    712             if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk)) {
    713                 return false;
    714             }
    715         }
    716 
    717         if (version != CompatibilityMatrix::kVersion) {
    718             this->mLastError = "Unrecognized compatibility-matrix.version";
    719             return false;
    720         }
    721         for (auto &&hal : hals) {
    722             if (!object->add(std::move(hal))) {
    723                 this->mLastError = "Duplicated compatibility-matrix.hal entry";
    724                 return false;
    725             }
    726         }
    727         return true;
    728     }
    729 };
    730 
    731 const CompatibilityMatrixConverter compatibilityMatrixConverter{};
    732 
    733 // Publicly available as in parse_xml.h
    734 const XmlConverter<HalManifest> &gHalManifestConverter = halManifestConverter;
    735 const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter
    736         = compatibilityMatrixConverter;
    737 
    738 // For testing in LibVintfTest
    739 const XmlConverter<Version> &gVersionConverter = versionConverter;
    740 const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter
    741         = kernelConfigTypedValueConverter;
    742 const XmlConverter<MatrixHal> &gMatrixHalConverter = matrixHalConverter;
    743 const XmlConverter<ManifestHal> &gManifestHalConverter = manifestHalConverter;
    744 
    745 } // namespace vintf
    746 } // namespace android
    747