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 #define LOG_TAG "libvintf" 20 #include <android-base/logging.h> 21 22 #include "parse_xml.h" 23 24 #include <type_traits> 25 26 #include <tinyxml2.h> 27 28 #include "parse_string.h" 29 30 namespace android { 31 namespace vintf { 32 33 // --------------- tinyxml2 details 34 35 using NodeType = tinyxml2::XMLElement; 36 using DocType = tinyxml2::XMLDocument; 37 38 // caller is responsible for deleteDocument() call 39 inline DocType *createDocument() { 40 return new tinyxml2::XMLDocument(); 41 } 42 43 // caller is responsible for deleteDocument() call 44 inline DocType *createDocument(const std::string &xml) { 45 DocType *doc = new tinyxml2::XMLDocument(); 46 if (doc->Parse(xml.c_str()) == tinyxml2::XML_NO_ERROR) { 47 return doc; 48 } 49 delete doc; 50 return nullptr; 51 } 52 53 inline void deleteDocument(DocType *d) { 54 delete d; 55 } 56 57 inline std::string printDocument(DocType *d) { 58 tinyxml2::XMLPrinter p; 59 d->Print(&p); 60 return std::string{p.CStr()}; 61 } 62 63 inline NodeType *createNode(const std::string &name, DocType *d) { 64 return d->NewElement(name.c_str()); 65 } 66 67 inline void appendChild(NodeType *parent, NodeType *child) { 68 parent->InsertEndChild(child); 69 } 70 71 inline void appendChild(DocType *parent, NodeType *child) { 72 parent->InsertEndChild(child); 73 } 74 75 inline void appendStrAttr(NodeType *e, const std::string &attrName, const std::string &attr) { 76 e->SetAttribute(attrName.c_str(), attr.c_str()); 77 } 78 79 // text -> text 80 inline void appendText(NodeType *parent, const std::string &text, DocType *d) { 81 parent->InsertEndChild(d->NewText(text.c_str())); 82 } 83 84 inline std::string nameOf(NodeType *root) { 85 return root->Name() == NULL ? "" : root->Name(); 86 } 87 88 inline std::string getText(NodeType *root) { 89 return root->GetText() == NULL ? "" : root->GetText(); 90 } 91 92 inline NodeType *getChild(NodeType *parent, const std::string &name) { 93 return parent->FirstChildElement(name.c_str()); 94 } 95 96 inline NodeType *getRootChild(DocType *parent) { 97 return parent->FirstChildElement(); 98 } 99 100 inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) { 101 std::vector<NodeType *> v; 102 for (NodeType *child = parent->FirstChildElement(name.c_str()); 103 child != nullptr; 104 child = child->NextSiblingElement(name.c_str())) { 105 v.push_back(child); 106 } 107 return v; 108 } 109 110 inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) { 111 const char *c = root->Attribute(attrName.c_str()); 112 if (c == NULL) 113 return false; 114 *s = c; 115 return true; 116 } 117 118 // --------------- tinyxml2 details end. 119 120 // Helper functions for XmlConverter 121 static bool parse(const std::string &attrText, bool *attr) { 122 if (attrText == "true" || attrText == "1") { 123 *attr = true; 124 return true; 125 } 126 if (attrText == "false" || attrText == "0") { 127 *attr = false; 128 return true; 129 } 130 return false; 131 } 132 133 // ---------------------- XmlNodeConverter definitions 134 135 template<typename Object> 136 struct XmlNodeConverter : public XmlConverter<Object> { 137 XmlNodeConverter() {} 138 virtual ~XmlNodeConverter() {} 139 140 // sub-types should implement these. 141 virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0; 142 virtual bool buildObject(Object *o, NodeType *n) const = 0; 143 virtual std::string elementName() const = 0; 144 145 // convenience methods for user 146 inline const std::string &lastError() const { return mLastError; } 147 inline NodeType *serialize(const Object &o, DocType *d) const { 148 NodeType *root = createNode(this->elementName(), d); 149 this->mutateNode(o, root, d); 150 return root; 151 } 152 inline std::string serialize(const Object &o) const { 153 DocType *doc = createDocument(); 154 appendChild(doc, serialize(o, doc)); 155 std::string s = printDocument(doc); 156 deleteDocument(doc); 157 return s; 158 } 159 inline bool deserialize(Object *object, NodeType *root) const { 160 if (nameOf(root) != this->elementName()) { 161 return false; 162 } 163 return this->buildObject(object, root); 164 } 165 inline bool deserialize(Object *o, const std::string &xml) const { 166 DocType *doc = createDocument(xml); 167 if (doc == nullptr) { 168 this->mLastError = "Not a valid XML"; 169 return false; 170 } 171 bool ret = deserialize(o, getRootChild(doc)); 172 deleteDocument(doc); 173 return ret; 174 } 175 inline NodeType *operator()(const Object &o, DocType *d) const { 176 return serialize(o, d); 177 } 178 inline std::string operator()(const Object &o) const { 179 return serialize(o); 180 } 181 inline bool operator()(Object *o, NodeType *node) const { 182 return deserialize(o, node); 183 } 184 inline bool operator()(Object *o, const std::string &xml) const { 185 return deserialize(o, xml); 186 } 187 188 // convenience methods for implementor. 189 190 // All append* functions helps mutateNode() to serialize the object into XML. 191 template <typename T> 192 inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const { 193 return appendStrAttr(e, attrName, ::android::vintf::to_string(attr)); 194 } 195 196 inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const { 197 return appendStrAttr(e, attrName, attr ? "true" : "false"); 198 } 199 200 // text -> <name>text</name> 201 inline void appendTextElement(NodeType *parent, const std::string &name, 202 const std::string &text, DocType *d) const { 203 NodeType *c = createNode(name, d); 204 appendText(c, text, d); 205 appendChild(parent, c); 206 } 207 208 // text -> <name>text</name> 209 template<typename Array> 210 inline void appendTextElements(NodeType *parent, const std::string &name, 211 const Array &array, DocType *d) const { 212 for (const std::string &text : array) { 213 NodeType *c = createNode(name, d); 214 appendText(c, text, d); 215 appendChild(parent, c); 216 } 217 } 218 219 template<typename T, typename Array> 220 inline void appendChildren(NodeType *parent, const XmlNodeConverter<T> &conv, 221 const Array &array, DocType *d) const { 222 for (const T &t : array) { 223 appendChild(parent, conv(t, d)); 224 } 225 } 226 227 // All parse* functions helps buildObject() to deserialize XML to the object. Returns 228 // true if deserialization is successful, false if any error, and mLastError will be 229 // set to error message. 230 template <typename T> 231 inline bool parseOptionalAttr(NodeType *root, const std::string &attrName, 232 T &&defaultValue, T *attr) const { 233 std::string attrText; 234 bool success = getAttr(root, attrName, &attrText) && 235 ::android::vintf::parse(attrText, attr); 236 if (!success) { 237 *attr = std::move(defaultValue); 238 } 239 return true; 240 } 241 242 template <typename T> 243 inline bool parseAttr(NodeType *root, const std::string &attrName, T *attr) const { 244 std::string attrText; 245 bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr); 246 if (!ret) { 247 mLastError = "Could not find/parse attr with name \"" + attrName + "\" and value \"" + 248 attrText + "\" for element <" + elementName() + ">"; 249 } 250 return ret; 251 } 252 253 inline bool parseAttr(NodeType *root, const std::string &attrName, std::string *attr) const { 254 bool ret = getAttr(root, attrName, attr); 255 if (!ret) { 256 mLastError = "Could not find attr with name \"" + attrName + "\" for element <" 257 + elementName() + ">"; 258 } 259 return ret; 260 } 261 262 inline bool parseTextElement(NodeType *root, 263 const std::string &elementName, std::string *s) const { 264 NodeType *child = getChild(root, elementName); 265 if (child == nullptr) { 266 mLastError = "Could not find element with name <" + elementName + "> in element <" 267 + this->elementName() + ">"; 268 return false; 269 } 270 *s = getText(child); 271 return true; 272 } 273 274 inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName, 275 std::string&& defaultValue, std::string* s) const { 276 NodeType* child = getChild(root, elementName); 277 *s = child == nullptr ? std::move(defaultValue) : getText(child); 278 return true; 279 } 280 281 inline bool parseTextElements(NodeType *root, const std::string &elementName, 282 std::vector<std::string> *v) const { 283 auto nodes = getChildren(root, elementName); 284 v->resize(nodes.size()); 285 for (size_t i = 0; i < nodes.size(); ++i) { 286 v->at(i) = getText(nodes[i]); 287 } 288 return true; 289 } 290 291 template <typename T> 292 inline bool parseChild(NodeType *root, const XmlNodeConverter<T> &conv, T *t) const { 293 NodeType *child = getChild(root, conv.elementName()); 294 if (child == nullptr) { 295 mLastError = "Could not find element with name <" + conv.elementName() + "> in element <" 296 + this->elementName() + ">"; 297 return false; 298 } 299 bool success = conv.deserialize(t, child); 300 if (!success) { 301 mLastError = conv.lastError(); 302 } 303 return success; 304 } 305 306 template <typename T> 307 inline bool parseOptionalChild(NodeType *root, const XmlNodeConverter<T> &conv, 308 T &&defaultValue, T *t) const { 309 NodeType *child = getChild(root, conv.elementName()); 310 if (child == nullptr) { 311 *t = std::move(defaultValue); 312 return true; 313 } 314 bool success = conv.deserialize(t, child); 315 if (!success) { 316 mLastError = conv.lastError(); 317 } 318 return success; 319 } 320 321 template <typename T> 322 inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::vector<T> *v) const { 323 auto nodes = getChildren(root, conv.elementName()); 324 v->resize(nodes.size()); 325 for (size_t i = 0; i < nodes.size(); ++i) { 326 if (!conv.deserialize(&v->at(i), nodes[i])) { 327 mLastError = "Could not parse element with name <" + conv.elementName() 328 + "> in element <" + this->elementName() + ">: " + conv.lastError(); 329 return false; 330 } 331 } 332 return true; 333 } 334 335 template <typename T> 336 inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::set<T> *s) const { 337 std::vector<T> vec; 338 if (!parseChildren(root, conv, &vec)) { 339 return false; 340 } 341 s->clear(); 342 s->insert(vec.begin(), vec.end()); 343 if (s->size() != vec.size()) { 344 mLastError = "Duplicated elements <" + conv.elementName() + "> in element <" 345 + this->elementName() + ">"; 346 s->clear(); 347 return false; 348 } 349 return true; 350 } 351 352 inline bool parseText(NodeType *node, std::string *s) const { 353 *s = getText(node); 354 return true; 355 } 356 357 template <typename T> 358 inline bool parseText(NodeType *node, T *s) const { 359 std::string text = getText(node); 360 bool ret = ::android::vintf::parse(text, s); 361 if (!ret) { 362 mLastError = "Could not parse text \"" + text + "\" in element <" + elementName() + ">"; 363 } 364 return ret; 365 } 366 protected: 367 mutable std::string mLastError; 368 }; 369 370 template<typename Object> 371 struct XmlTextConverter : public XmlNodeConverter<Object> { 372 XmlTextConverter(const std::string &elementName) 373 : mElementName(elementName) {} 374 375 virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override { 376 appendText(root, ::android::vintf::to_string(object), d); 377 } 378 virtual bool buildObject(Object *object, NodeType *root) const override { 379 return this->parseText(root, object); 380 } 381 virtual std::string elementName() const { return mElementName; }; 382 private: 383 std::string mElementName; 384 }; 385 386 // ---------------------- XmlNodeConverter definitions end 387 388 const XmlTextConverter<Version> versionConverter{"version"}; 389 390 const XmlTextConverter<VersionRange> versionRangeConverter{"version"}; 391 392 const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"}; 393 394 struct TransportArchConverter : public XmlNodeConverter<TransportArch> { 395 std::string elementName() const override { return "transport"; } 396 void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override { 397 if (object.arch != Arch::ARCH_EMPTY) { 398 appendAttr(root, "arch", object.arch); 399 } 400 appendText(root, ::android::vintf::to_string(object.transport), d); 401 } 402 bool buildObject(TransportArch *object, NodeType *root) const override { 403 if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch) || 404 !parseText(root, &object->transport)) { 405 return false; 406 } 407 if (!object->isValid()) { 408 this->mLastError = "transport == " + ::android::vintf::to_string(object->transport) + 409 " and arch == " + ::android::vintf::to_string(object->arch) + 410 " is not a valid combination."; 411 return false; 412 } 413 return true; 414 } 415 }; 416 417 const TransportArchConverter transportArchConverter{}; 418 419 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> { 420 std::string elementName() const override { return "value"; } 421 void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override { 422 appendAttr(root, "type", object.mType); 423 appendText(root, ::android::vintf::to_string(object), d); 424 } 425 bool buildObject(KernelConfigTypedValue *object, NodeType *root) const override { 426 std::string stringValue; 427 if (!parseAttr(root, "type", &object->mType) || 428 !parseText(root, &stringValue)) { 429 return false; 430 } 431 if (!::android::vintf::parseKernelConfigValue(stringValue, object)) { 432 this->mLastError = "Could not parse kernel config value \"" + stringValue + "\""; 433 return false; 434 } 435 return true; 436 } 437 }; 438 439 const KernelConfigTypedValueConverter kernelConfigTypedValueConverter{}; 440 441 struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> { 442 std::string elementName() const override { return "config"; } 443 void mutateNode(const KernelConfig &object, NodeType *root, DocType *d) const override { 444 appendChild(root, kernelConfigKeyConverter(object.first, d)); 445 appendChild(root, kernelConfigTypedValueConverter(object.second, d)); 446 } 447 bool buildObject(KernelConfig *object, NodeType *root) const override { 448 if ( !parseChild(root, kernelConfigKeyConverter, &object->first) 449 || !parseChild(root, kernelConfigTypedValueConverter, &object->second)) { 450 return false; 451 } 452 return true; 453 } 454 }; 455 456 const KernelConfigConverter kernelConfigConverter{}; 457 458 struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> { 459 std::string elementName() const override { return "interface"; } 460 void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override { 461 appendTextElement(root, "name", intf.name, d); 462 appendTextElements(root, "instance", intf.instances, d); 463 } 464 bool buildObject(HalInterface *intf, NodeType *root) const override { 465 std::vector<std::string> instances; 466 if (!parseTextElement(root, "name", &intf->name) || 467 !parseTextElements(root, "instance", &instances)) { 468 return false; 469 } 470 intf->instances.clear(); 471 intf->instances.insert(instances.begin(), instances.end()); 472 if (intf->instances.size() != instances.size()) { 473 this->mLastError = "Duplicated instances in " + intf->name; 474 return false; 475 } 476 return true; 477 } 478 }; 479 480 const HalInterfaceConverter halInterfaceConverter{}; 481 482 struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> { 483 std::string elementName() const override { return "hal"; } 484 void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override { 485 appendAttr(root, "format", hal.format); 486 appendAttr(root, "optional", hal.optional); 487 appendTextElement(root, "name", hal.name, d); 488 appendChildren(root, versionRangeConverter, hal.versionRanges, d); 489 appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d); 490 } 491 bool buildObject(MatrixHal *object, NodeType *root) const override { 492 std::vector<HalInterface> interfaces; 493 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) || 494 !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional) || 495 !parseTextElement(root, "name", &object->name) || 496 !parseChildren(root, versionRangeConverter, &object->versionRanges) || 497 !parseChildren(root, halInterfaceConverter, &interfaces)) { 498 return false; 499 } 500 for (auto&& interface : interfaces) { 501 std::string name{interface.name}; 502 auto res = object->interfaces.emplace(std::move(name), std::move(interface)); 503 if (!res.second) { 504 this->mLastError = "Duplicated interface entry \"" + res.first->first + 505 "\"; if additional instances are needed, add them to the " 506 "existing <interface> node."; 507 return false; 508 } 509 } 510 // Do not check for target-side libvintf to avoid restricting ability for upgrade accidentally. 511 #ifdef LIBVINTF_HOST 512 if (!checkAdditionalRestrictionsOnHal(*object)) { 513 return false; 514 } 515 #endif 516 return true; 517 } 518 519 #ifdef LIBVINTF_HOST 520 private: 521 bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal) const { 522 if (hal.getName() == "netutils-wrapper") { 523 if (hal.versionRanges.size() != 1) { 524 this->mLastError = 525 "netutils-wrapper HAL must specify exactly one version x.0, " 526 "but multiple <version> element is specified."; 527 return false; 528 } 529 const VersionRange& v = hal.versionRanges.at(0); 530 if (!v.isSingleVersion()) { 531 this->mLastError = 532 "netutils-wrapper HAL must specify exactly one version x.0, " 533 "but a range is provided. Perhaps you mean '" + 534 to_string(Version{v.majorVer, 0}) + "'?"; 535 return false; 536 } 537 if (v.minMinor != 0) { 538 this->mLastError = 539 "netutils-wrapper HAL must specify exactly one version x.0, " 540 "but minor version is not 0. Perhaps you mean '" + 541 to_string(Version{v.majorVer, 0}) + "'?"; 542 return false; 543 } 544 } 545 return true; 546 } 547 #endif 548 }; 549 550 const MatrixHalConverter matrixHalConverter{}; 551 552 struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> { 553 std::string elementName() const override { return "conditions"; } 554 void mutateNode(const std::vector<KernelConfig>& conds, NodeType* root, 555 DocType* d) const override { 556 appendChildren(root, kernelConfigConverter, conds, d); 557 } 558 bool buildObject(std::vector<KernelConfig>* object, NodeType* root) const override { 559 return parseChildren(root, kernelConfigConverter, object); 560 } 561 }; 562 563 const MatrixKernelConditionsConverter matrixKernelConditionsConverter{}; 564 565 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> { 566 std::string elementName() const override { return "kernel"; } 567 void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override { 568 appendAttr(root, "version", kernel.mMinLts); 569 if (!kernel.mConditions.empty()) { 570 appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d)); 571 } 572 appendChildren(root, kernelConfigConverter, kernel.mConfigs, d); 573 } 574 bool buildObject(MatrixKernel *object, NodeType *root) const override { 575 if (!parseAttr(root, "version", &object->mMinLts) || 576 !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions) || 577 !parseChildren(root, kernelConfigConverter, &object->mConfigs)) { 578 return false; 579 } 580 return true; 581 } 582 }; 583 584 const MatrixKernelConverter matrixKernelConverter{}; 585 586 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> { 587 std::string elementName() const override { return "hal"; } 588 void mutateNode(const ManifestHal &hal, NodeType *root, DocType *d) const override { 589 appendAttr(root, "format", hal.format); 590 appendTextElement(root, "name", hal.name, d); 591 appendChild(root, transportArchConverter(hal.transportArch, d)); 592 appendChildren(root, versionConverter, hal.versions, d); 593 appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d); 594 } 595 bool buildObject(ManifestHal *object, NodeType *root) const override { 596 std::vector<HalInterface> interfaces; 597 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) || 598 !parseTextElement(root, "name", &object->name) || 599 !parseOptionalChild(root, transportArchConverter, {}, &object->transportArch) || 600 !parseChildren(root, versionConverter, &object->versions) || 601 !parseChildren(root, halInterfaceConverter, &interfaces)) { 602 return false; 603 } 604 605 switch (object->format) { 606 case HalFormat::HIDL: { 607 if (object->transportArch.empty()) { 608 this->mLastError = 609 "HIDL HAL '" + object->name + "' should have <transport> defined."; 610 return false; 611 } 612 } break; 613 case HalFormat::NATIVE: { 614 if (!object->transportArch.empty()) { 615 this->mLastError = 616 "Native HAL '" + object->name + "' should not have <transport> defined."; 617 return false; 618 } 619 } break; 620 default: { 621 LOG(FATAL) << "Unhandled HalFormat " 622 << static_cast<typename std::underlying_type<HalFormat>::type>( 623 object->format); 624 } break; 625 } 626 if (!object->transportArch.isValid()) return false; 627 628 object->interfaces.clear(); 629 for (auto &&interface : interfaces) { 630 auto res = object->interfaces.emplace(interface.name, 631 std::move(interface)); 632 if (!res.second) { 633 this->mLastError = "Duplicated interface entry \"" + res.first->first + 634 "\"; if additional instances are needed, add them to the " 635 "existing <interface> node."; 636 return false; 637 } 638 } 639 if (!object->isValid()) { 640 this->mLastError = "'" + object->name + "' is not a valid Manifest HAL."; 641 return false; 642 } 643 // Do not check for target-side libvintf to avoid restricting upgrade accidentally. 644 #ifdef LIBVINTF_HOST 645 if (!checkAdditionalRestrictionsOnHal(*object)) { 646 return false; 647 } 648 #endif 649 return true; 650 } 651 652 #ifdef LIBVINTF_HOST 653 private: 654 bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal) const { 655 if (hal.getName() == "netutils-wrapper") { 656 for (const Version& v : hal.versions) { 657 if (v.minorVer != 0) { 658 this->mLastError = 659 "netutils-wrapper HAL must specify exactly one version x.0, " 660 "but minor version is not 0. Perhaps you mean '" + 661 to_string(Version{v.majorVer, 0}) + "'?"; 662 return false; 663 } 664 } 665 } 666 return true; 667 } 668 #endif 669 }; 670 671 // Convert ManifestHal from and to XML. Returned object is guaranteed to have 672 // .isValid() == true. 673 const ManifestHalConverter manifestHalConverter{}; 674 675 const XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"}; 676 const XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"}; 677 678 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> { 679 std::string elementName() const override { return "sepolicy"; } 680 void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override { 681 appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d)); 682 appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d); 683 } 684 bool buildObject(Sepolicy *object, NodeType *root) const override { 685 if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion) || 686 !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges)) { 687 return false; 688 } 689 return true; 690 } 691 }; 692 const SepolicyConverter sepolicyConverter{}; 693 694 const XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"}; 695 const XmlTextConverter<std::string> vndkLibraryConverter{"library"}; 696 697 struct VndkConverter : public XmlNodeConverter<Vndk> { 698 std::string elementName() const override { return "vndk"; } 699 void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override { 700 appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d)); 701 appendChildren(root, vndkLibraryConverter, object.mLibraries, d); 702 } 703 bool buildObject(Vndk *object, NodeType *root) const override { 704 if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange) || 705 !parseChildren(root, vndkLibraryConverter, &object->mLibraries)) { 706 return false; 707 } 708 return true; 709 } 710 }; 711 712 const VndkConverter vndkConverter{}; 713 714 struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> { 715 std::string elementName() const override { return "sepolicy"; } 716 void mutateNode(const Version &m, NodeType *root, DocType *d) const override { 717 appendChild(root, versionConverter(m, d)); 718 } 719 bool buildObject(Version *object, NodeType *root) const override { 720 return parseChild(root, versionConverter, object); 721 } 722 }; 723 const HalManifestSepolicyConverter halManifestSepolicyConverter{}; 724 725 struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> { 726 std::string elementName() const override { return "xmlfile"; } 727 void mutateNode(const ManifestXmlFile& f, NodeType* root, DocType* d) const override { 728 appendTextElement(root, "name", f.name(), d); 729 appendChild(root, versionConverter(f.version(), d)); 730 if (!f.overriddenPath().empty()) { 731 appendTextElement(root, "path", f.overriddenPath(), d); 732 } 733 } 734 bool buildObject(ManifestXmlFile* object, NodeType* root) const override { 735 if (!parseTextElement(root, "name", &object->mName) || 736 !parseChild(root, versionConverter, &object->mVersion) || 737 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath)) { 738 return false; 739 } 740 return true; 741 } 742 }; 743 const ManifestXmlFileConverter manifestXmlFileConverter{}; 744 745 struct HalManifestConverter : public XmlNodeConverter<HalManifest> { 746 std::string elementName() const override { return "manifest"; } 747 void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override { 748 appendAttr(root, "version", HalManifest::kVersion); 749 appendAttr(root, "type", m.mType); 750 751 appendChildren(root, manifestHalConverter, m.getHals(), d); 752 if (m.mType == SchemaType::DEVICE) { 753 appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d)); 754 } else if (m.mType == SchemaType::FRAMEWORK) { 755 appendChildren(root, vndkConverter, m.framework.mVndks, d); 756 } 757 758 appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d); 759 } 760 bool buildObject(HalManifest *object, NodeType *root) const override { 761 Version version; 762 std::vector<ManifestHal> hals; 763 if (!parseAttr(root, "version", &version) || 764 !parseAttr(root, "type", &object->mType) || 765 !parseChildren(root, manifestHalConverter, &hals)) { 766 return false; 767 } 768 if (version != HalManifest::kVersion) { 769 this->mLastError = "Unrecognized manifest.version"; 770 return false; 771 } 772 if (object->mType == SchemaType::DEVICE) { 773 // tags for device hal manifest only. 774 // <sepolicy> can be missing because it can be determined at build time, not hard-coded 775 // in the XML file. 776 if (!parseOptionalChild(root, halManifestSepolicyConverter, {}, 777 &object->device.mSepolicyVersion)) { 778 return false; 779 } 780 } else if (object->mType == SchemaType::FRAMEWORK) { 781 if (!parseChildren(root, vndkConverter, &object->framework.mVndks)) { 782 return false; 783 } 784 for (const auto &vndk : object->framework.mVndks) { 785 if (!vndk.mVersionRange.isSingleVersion()) { 786 this->mLastError = "vndk.version " + to_string(vndk.mVersionRange) 787 + " cannot be a range for manifests"; 788 return false; 789 } 790 } 791 } 792 for (auto &&hal : hals) { 793 std::string description{hal.name}; 794 if (!object->add(std::move(hal))) { 795 this->mLastError = "Duplicated manifest.hal entry " + description; 796 return false; 797 } 798 } 799 800 std::vector<ManifestXmlFile> xmlFiles; 801 if (!parseChildren(root, manifestXmlFileConverter, &xmlFiles)) { 802 return false; 803 } 804 for (auto&& xmlFile : xmlFiles) { 805 std::string description{xmlFile.name()}; 806 if (!object->addXmlFile(std::move(xmlFile))) { 807 this->mLastError = "Duplicated manifest.xmlfile entry " + description + 808 "; entries cannot have duplicated name and version"; 809 return false; 810 } 811 } 812 813 return true; 814 } 815 }; 816 817 const HalManifestConverter halManifestConverter{}; 818 819 const XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"}; 820 struct AvbConverter : public XmlNodeConverter<Version> { 821 std::string elementName() const override { return "avb"; } 822 void mutateNode(const Version &m, NodeType *root, DocType *d) const override { 823 appendChild(root, avbVersionConverter(m, d)); 824 } 825 bool buildObject(Version *object, NodeType *root) const override { 826 return parseChild(root, avbVersionConverter, object); 827 } 828 }; 829 const AvbConverter avbConverter{}; 830 831 struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> { 832 std::string elementName() const override { return "xmlfile"; } 833 void mutateNode(const MatrixXmlFile& f, NodeType* root, DocType* d) const override { 834 appendTextElement(root, "name", f.name(), d); 835 appendAttr(root, "format", f.format()); 836 appendAttr(root, "optional", f.optional()); 837 appendChild(root, versionRangeConverter(f.versionRange(), d)); 838 if (!f.overriddenPath().empty()) { 839 appendTextElement(root, "path", f.overriddenPath(), d); 840 } 841 } 842 bool buildObject(MatrixXmlFile* object, NodeType* root) const override { 843 if (!parseTextElement(root, "name", &object->mName) || 844 !parseAttr(root, "format", &object->mFormat) || 845 !parseOptionalAttr(root, "optional", false, &object->mOptional) || 846 !parseChild(root, versionRangeConverter, &object->mVersionRange) || 847 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath)) { 848 return false; 849 } 850 return true; 851 } 852 }; 853 const MatrixXmlFileConverter matrixXmlFileConverter{}; 854 855 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> { 856 std::string elementName() const override { return "compatibility-matrix"; } 857 void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override { 858 appendAttr(root, "version", CompatibilityMatrix::kVersion); 859 appendAttr(root, "type", m.mType); 860 appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d); 861 if (m.mType == SchemaType::FRAMEWORK) { 862 appendChildren(root, matrixKernelConverter, m.framework.mKernels, d); 863 appendChild(root, sepolicyConverter(m.framework.mSepolicy, d)); 864 appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d)); 865 } else if (m.mType == SchemaType::DEVICE) { 866 appendChild(root, vndkConverter(m.device.mVndk, d)); 867 } 868 869 appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d); 870 } 871 bool buildObject(CompatibilityMatrix *object, NodeType *root) const override { 872 Version version; 873 std::vector<MatrixHal> hals; 874 if (!parseAttr(root, "version", &version) || 875 !parseAttr(root, "type", &object->mType) || 876 !parseChildren(root, matrixHalConverter, &hals)) { 877 return false; 878 } 879 880 if (object->mType == SchemaType::FRAMEWORK) { 881 // <avb> and <sepolicy> can be missing because it can be determined at build time, not 882 // hard-coded in the XML file. 883 if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels) || 884 !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy) || 885 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion)) { 886 return false; 887 } 888 889 std::set<Version> seenKernelVersions; 890 for (const auto& kernel : object->framework.mKernels) { 891 Version minLts(kernel.minLts().version, kernel.minLts().majorRev); 892 if (seenKernelVersions.find(minLts) != seenKernelVersions.end()) { 893 continue; 894 } 895 if (!kernel.conditions().empty()) { 896 this->mLastError = "First <kernel> for version " + to_string(minLts) + 897 " must have empty <conditions> for backwards compatibility."; 898 return false; 899 } 900 seenKernelVersions.insert(minLts); 901 } 902 903 } else if (object->mType == SchemaType::DEVICE) { 904 // <vndk> can be missing because it can be determined at build time, not hard-coded 905 // in the XML file. 906 if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk)) { 907 return false; 908 } 909 } 910 911 if (version != CompatibilityMatrix::kVersion) { 912 this->mLastError = "Unrecognized compatibility-matrix.version"; 913 return false; 914 } 915 for (auto &&hal : hals) { 916 if (!object->add(std::move(hal))) { 917 this->mLastError = "Duplicated compatibility-matrix.hal entry"; 918 return false; 919 } 920 } 921 922 std::vector<MatrixXmlFile> xmlFiles; 923 if (!parseChildren(root, matrixXmlFileConverter, &xmlFiles)) { 924 return false; 925 } 926 for (auto&& xmlFile : xmlFiles) { 927 if (!xmlFile.optional()) { 928 this->mLastError = "compatibility-matrix.xmlfile entry " + xmlFile.name() + 929 " has to be optional for compatibility matrix version 1.0"; 930 return false; 931 } 932 std::string description{xmlFile.name()}; 933 if (!object->addXmlFile(std::move(xmlFile))) { 934 this->mLastError = "Duplicated compatibility-matrix.xmlfile entry " + description; 935 return false; 936 } 937 } 938 939 return true; 940 } 941 }; 942 943 const CompatibilityMatrixConverter compatibilityMatrixConverter{}; 944 945 // Publicly available as in parse_xml.h 946 const XmlConverter<HalManifest> &gHalManifestConverter = halManifestConverter; 947 const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter 948 = compatibilityMatrixConverter; 949 950 // For testing in LibVintfTest 951 const XmlConverter<Version> &gVersionConverter = versionConverter; 952 const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter 953 = kernelConfigTypedValueConverter; 954 const XmlConverter<MatrixHal> &gMatrixHalConverter = matrixHalConverter; 955 const XmlConverter<ManifestHal> &gManifestHalConverter = manifestHalConverter; 956 957 } // namespace vintf 958 } // namespace android 959