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 24namespace android { 25namespace vintf { 26 27// --------------- tinyxml2 details 28 29using NodeType = tinyxml2::XMLElement; 30using DocType = tinyxml2::XMLDocument; 31 32// caller is responsible for deleteDocument() call 33inline DocType *createDocument() { 34 return new tinyxml2::XMLDocument(); 35} 36 37// caller is responsible for deleteDocument() call 38inline 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 47inline void deleteDocument(DocType *d) { 48 delete d; 49} 50 51inline std::string printDocument(DocType *d) { 52 tinyxml2::XMLPrinter p; 53 d->Print(&p); 54 return std::string{p.CStr()}; 55} 56 57inline NodeType *createNode(const std::string &name, DocType *d) { 58 return d->NewElement(name.c_str()); 59} 60 61inline void appendChild(NodeType *parent, NodeType *child) { 62 parent->InsertEndChild(child); 63} 64 65inline void appendChild(DocType *parent, NodeType *child) { 66 parent->InsertEndChild(child); 67} 68 69inline 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 74inline void appendText(NodeType *parent, const std::string &text, DocType *d) { 75 parent->InsertEndChild(d->NewText(text.c_str())); 76} 77 78inline std::string nameOf(NodeType *root) { 79 return root->Name() == NULL ? "" : root->Name(); 80} 81 82inline std::string getText(NodeType *root) { 83 return root->GetText() == NULL ? "" : root->GetText(); 84} 85 86inline NodeType *getChild(NodeType *parent, const std::string &name) { 87 return parent->FirstChildElement(name.c_str()); 88} 89 90inline NodeType *getRootChild(DocType *parent) { 91 return parent->FirstChildElement(); 92} 93 94inline 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 104inline 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 115static 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 129template<typename Object> 130struct 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 } 353protected: 354 mutable std::string mLastError; 355}; 356 357template<typename Object> 358struct 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; }; 369private: 370 std::string mElementName; 371}; 372 373// ---------------------- XmlNodeConverter definitions end 374 375const XmlTextConverter<Version> versionConverter{"version"}; 376 377const XmlTextConverter<VersionRange> versionRangeConverter{"version"}; 378 379const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"}; 380 381struct 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 404const TransportArchConverter transportArchConverter{}; 405 406struct 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 426const KernelConfigTypedValueConverter kernelConfigTypedValueConverter{}; 427 428struct 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 443const KernelConfigConverter kernelConfigConverter{}; 444 445struct 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 467const HalInterfaceConverter halInterfaceConverter{}; 468 469struct 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 499const MatrixHalConverter matrixHalConverter{}; 500 501struct 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 516const MatrixKernelConverter matrixKernelConverter{}; 517 518struct 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. 557const ManifestHalConverter manifestHalConverter{}; 558 559const XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"}; 560const XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"}; 561 562struct 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}; 576const SepolicyConverter sepolicyConverter{}; 577 578const XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"}; 579const XmlTextConverter<std::string> vndkLibraryConverter{"library"}; 580 581struct 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 596const VndkConverter vndkConverter{}; 597 598struct 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}; 607const HalManifestSepolicyConverter halManifestSepolicyConverter{}; 608 609struct 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 664const HalManifestConverter halManifestConverter{}; 665 666const XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"}; 667struct 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}; 676const AvbConverter avbConverter{}; 677 678struct 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 731const CompatibilityMatrixConverter compatibilityMatrixConverter{}; 732 733// Publicly available as in parse_xml.h 734const XmlConverter<HalManifest> &gHalManifestConverter = halManifestConverter; 735const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter 736 = compatibilityMatrixConverter; 737 738// For testing in LibVintfTest 739const XmlConverter<Version> &gVersionConverter = versionConverter; 740const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter 741 = kernelConfigTypedValueConverter; 742const XmlConverter<MatrixHal> &gMatrixHalConverter = matrixHalConverter; 743const XmlConverter<ManifestHal> &gManifestHalConverter = manifestHalConverter; 744 745} // namespace vintf 746} // namespace android 747