/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Convert objects from and to xml. #define LOG_TAG "libvintf" #include <android-base/logging.h> #include "parse_xml.h" #include <type_traits> #include <tinyxml2.h> #include "Regex.h" #include "constants.h" #include "parse_string.h" namespace android { namespace vintf { // --------------- tinyxml2 details using NodeType = tinyxml2::XMLElement; using DocType = tinyxml2::XMLDocument; // caller is responsible for deleteDocument() call inline DocType *createDocument() { return new tinyxml2::XMLDocument(); } // caller is responsible for deleteDocument() call inline DocType *createDocument(const std::string &xml) { DocType *doc = new tinyxml2::XMLDocument(); if (doc->Parse(xml.c_str()) == tinyxml2::XML_SUCCESS) { return doc; } delete doc; return nullptr; } inline void deleteDocument(DocType *d) { delete d; } inline std::string printDocument(DocType *d) { tinyxml2::XMLPrinter p; d->Print(&p); return std::string{p.CStr()}; } inline NodeType *createNode(const std::string &name, DocType *d) { return d->NewElement(name.c_str()); } inline void appendChild(NodeType *parent, NodeType *child) { parent->InsertEndChild(child); } inline void appendChild(DocType *parent, NodeType *child) { parent->InsertEndChild(child); } inline void appendStrAttr(NodeType *e, const std::string &attrName, const std::string &attr) { e->SetAttribute(attrName.c_str(), attr.c_str()); } // text -> text inline void appendText(NodeType *parent, const std::string &text, DocType *d) { parent->InsertEndChild(d->NewText(text.c_str())); } inline std::string nameOf(NodeType *root) { return root->Name() == NULL ? "" : root->Name(); } inline std::string getText(NodeType *root) { return root->GetText() == NULL ? "" : root->GetText(); } inline NodeType *getChild(NodeType *parent, const std::string &name) { return parent->FirstChildElement(name.c_str()); } inline NodeType *getRootChild(DocType *parent) { return parent->FirstChildElement(); } inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) { std::vector<NodeType *> v; for (NodeType *child = parent->FirstChildElement(name.c_str()); child != nullptr; child = child->NextSiblingElement(name.c_str())) { v.push_back(child); } return v; } inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) { const char *c = root->Attribute(attrName.c_str()); if (c == NULL) return false; *s = c; return true; } // --------------- tinyxml2 details end. // Helper functions for XmlConverter static bool parse(const std::string &attrText, bool *attr) { if (attrText == "true" || attrText == "1") { *attr = true; return true; } if (attrText == "false" || attrText == "0") { *attr = false; return true; } return false; } // ---------------------- XmlNodeConverter definitions template<typename Object> struct XmlNodeConverter : public XmlConverter<Object> { XmlNodeConverter() {} virtual ~XmlNodeConverter() {} // sub-types should implement these. virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0; virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags) const { mutateNode(o, n, d); } virtual bool buildObject(Object* o, NodeType* n, std::string* error) const = 0; virtual std::string elementName() const = 0; // convenience methods for user inline const std::string& lastError() const override { return mLastError; } inline NodeType* serialize(const Object& o, DocType* d, SerializeFlags flags = EVERYTHING) const { NodeType *root = createNode(this->elementName(), d); this->mutateNode(o, root, d, flags); return root; } inline std::string serialize(const Object& o, SerializeFlags flags) const override { DocType *doc = createDocument(); appendChild(doc, serialize(o, doc, flags)); std::string s = printDocument(doc); deleteDocument(doc); return s; } inline bool deserialize(Object* object, NodeType* root) { bool ret = deserialize(object, root, &mLastError); return ret; } inline bool deserialize(Object* o, const std::string& xml) override { bool ret = (*this)(o, xml, &mLastError); return ret; } inline bool deserialize(Object* object, NodeType* root, std::string* error) const { if (nameOf(root) != this->elementName()) { return false; } return this->buildObject(object, root, error); } inline bool operator()(Object* o, const std::string& xml, std::string* error) const override { std::string errorBuffer; if (error == nullptr) error = &errorBuffer; auto doc = createDocument(xml); if (doc == nullptr) { *error = "Not a valid XML"; return false; } bool ret = deserialize(o, getRootChild(doc), error); deleteDocument(doc); return ret; } inline NodeType *operator()(const Object &o, DocType *d) const { return serialize(o, d); } inline std::string operator()(const Object& o, SerializeFlags flags) const override { return serialize(o, flags); } inline bool operator()(Object* o, NodeType* node) { return deserialize(o, node); } inline bool operator()(Object* o, const std::string& xml) override { return deserialize(o, xml); } // convenience methods for implementor. // All append* functions helps mutateNode() to serialize the object into XML. template <typename T> inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const { return appendStrAttr(e, attrName, ::android::vintf::to_string(attr)); } inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const { return appendStrAttr(e, attrName, attr ? "true" : "false"); } // text -> <name>text</name> inline void appendTextElement(NodeType *parent, const std::string &name, const std::string &text, DocType *d) const { NodeType *c = createNode(name, d); appendText(c, text, d); appendChild(parent, c); } // text -> <name>text</name> template<typename Array> inline void appendTextElements(NodeType *parent, const std::string &name, const Array &array, DocType *d) const { for (const std::string &text : array) { NodeType *c = createNode(name, d); appendText(c, text, d); appendChild(parent, c); } } template <typename T, typename Array> inline void appendChildren(NodeType* parent, const XmlNodeConverter<T>& conv, const Array& array, DocType* d, SerializeFlags flags = SerializeFlag::EVERYTHING) const { for (const T &t : array) { appendChild(parent, conv.serialize(t, d, flags)); } } // All parse* functions helps buildObject() to deserialize XML to the object. Returns // true if deserialization is successful, false if any error, and "error" will be // set to error message. template <typename T> inline bool parseOptionalAttr(NodeType* root, const std::string& attrName, T&& defaultValue, T* attr, std::string* /* error */) const { std::string attrText; bool success = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr); if (!success) { *attr = std::move(defaultValue); } return true; } template <typename T> inline bool parseAttr(NodeType* root, const std::string& attrName, T* attr, std::string* error) const { std::string attrText; bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr); if (!ret) { *error = "Could not find/parse attr with name \"" + attrName + "\" and value \"" + attrText + "\" for element <" + elementName() + ">"; } return ret; } inline bool parseAttr(NodeType* root, const std::string& attrName, std::string* attr, std::string* error) const { bool ret = getAttr(root, attrName, attr); if (!ret) { *error = "Could not find attr with name \"" + attrName + "\" for element <" + elementName() + ">"; } return ret; } inline bool parseTextElement(NodeType* root, const std::string& elementName, std::string* s, std::string* error) const { NodeType *child = getChild(root, elementName); if (child == nullptr) { *error = "Could not find element with name <" + elementName + "> in element <" + this->elementName() + ">"; return false; } *s = getText(child); return true; } inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName, std::string&& defaultValue, std::string* s, std::string* /* error */) const { NodeType* child = getChild(root, elementName); *s = child == nullptr ? std::move(defaultValue) : getText(child); return true; } inline bool parseTextElements(NodeType* root, const std::string& elementName, std::vector<std::string>* v, std::string* /* error */) const { auto nodes = getChildren(root, elementName); v->resize(nodes.size()); for (size_t i = 0; i < nodes.size(); ++i) { v->at(i) = getText(nodes[i]); } return true; } template <typename T> inline bool parseChild(NodeType* root, const XmlNodeConverter<T>& conv, T* t, std::string* error) const { NodeType *child = getChild(root, conv.elementName()); if (child == nullptr) { *error = "Could not find element with name <" + conv.elementName() + "> in element <" + this->elementName() + ">"; return false; } return conv.deserialize(t, child, error); } template <typename T> inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv, T&& defaultValue, T* t, std::string* error) const { NodeType *child = getChild(root, conv.elementName()); if (child == nullptr) { *t = std::move(defaultValue); return true; } return conv.deserialize(t, child, error); } template <typename T> inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v, std::string* error) const { auto nodes = getChildren(root, conv.elementName()); v->resize(nodes.size()); for (size_t i = 0; i < nodes.size(); ++i) { if (!conv.deserialize(&v->at(i), nodes[i], error)) { *error = "Could not parse element with name <" + conv.elementName() + "> in element <" + this->elementName() + ">: " + *error; return false; } } return true; } template <typename T> inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::set<T>* s, std::string* error) const { std::vector<T> vec; if (!parseChildren(root, conv, &vec, error)) { return false; } s->clear(); s->insert(vec.begin(), vec.end()); if (s->size() != vec.size()) { *error = "Duplicated elements <" + conv.elementName() + "> in element <" + this->elementName() + ">"; s->clear(); return false; } return true; } inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const { *s = getText(node); return true; } template <typename T> inline bool parseText(NodeType* node, T* s, std::string* error) const { std::string text = getText(node); bool ret = ::android::vintf::parse(text, s); if (!ret) { *error = "Could not parse text \"" + text + "\" in element <" + elementName() + ">"; } return ret; } private: mutable std::string mLastError; }; template<typename Object> struct XmlTextConverter : public XmlNodeConverter<Object> { XmlTextConverter(const std::string &elementName) : mElementName(elementName) {} virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override { appendText(root, ::android::vintf::to_string(object), d); } virtual bool buildObject(Object* object, NodeType* root, std::string* error) const override { return this->parseText(root, object, error); } virtual std::string elementName() const { return mElementName; }; private: std::string mElementName; }; // ---------------------- XmlNodeConverter definitions end XmlTextConverter<Version> versionConverter{"version"}; XmlTextConverter<VersionRange> versionRangeConverter{"version"}; XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"}; struct TransportArchConverter : public XmlNodeConverter<TransportArch> { std::string elementName() const override { return "transport"; } void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override { if (object.arch != Arch::ARCH_EMPTY) { appendAttr(root, "arch", object.arch); } appendText(root, ::android::vintf::to_string(object.transport), d); } bool buildObject(TransportArch* object, NodeType* root, std::string* error) const override { if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, error) || !parseText(root, &object->transport, error)) { return false; } if (!object->isValid()) { *error = "transport == " + ::android::vintf::to_string(object->transport) + " and arch == " + ::android::vintf::to_string(object->arch) + " is not a valid combination."; return false; } return true; } }; TransportArchConverter transportArchConverter{}; struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> { std::string elementName() const override { return "value"; } void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override { appendAttr(root, "type", object.mType); appendText(root, ::android::vintf::to_string(object), d); } bool buildObject(KernelConfigTypedValue* object, NodeType* root, std::string* error) const override { std::string stringValue; if (!parseAttr(root, "type", &object->mType, error) || !parseText(root, &stringValue, error)) { return false; } if (!::android::vintf::parseKernelConfigValue(stringValue, object)) { *error = "Could not parse kernel config value \"" + stringValue + "\""; return false; } return true; } }; KernelConfigTypedValueConverter kernelConfigTypedValueConverter{}; struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> { std::string elementName() const override { return "config"; } void mutateNode(const KernelConfig &object, NodeType *root, DocType *d) const override { appendChild(root, kernelConfigKeyConverter(object.first, d)); appendChild(root, kernelConfigTypedValueConverter(object.second, d)); } bool buildObject(KernelConfig* object, NodeType* root, std::string* error) const override { if (!parseChild(root, kernelConfigKeyConverter, &object->first, error) || !parseChild(root, kernelConfigTypedValueConverter, &object->second, error)) { return false; } return true; } }; KernelConfigConverter kernelConfigConverter{}; struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> { std::string elementName() const override { return "interface"; } void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override { appendTextElement(root, "name", intf.name(), d); appendTextElements(root, "instance", intf.mInstances, d); appendTextElements(root, "regex-instance", intf.mRegexes, d); } bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override { std::vector<std::string> instances; std::vector<std::string> regexes; if (!parseTextElement(root, "name", &intf->mName, error) || !parseTextElements(root, "instance", &instances, error) || !parseTextElements(root, "regex-instance", ®exes, error)) { return false; } bool success = true; for (const auto& e : instances) { if (!intf->insertInstance(e, false /* isRegex */)) { if (!error->empty()) *error += "\n"; *error += "Duplicated instance '" + e + "' in " + intf->name(); success = false; } } for (const auto& e : regexes) { details::Regex regex; if (!regex.compile(e)) { if (!error->empty()) *error += "\n"; *error += "Invalid regular expression '" + e + "' in " + intf->name(); success = false; } if (!intf->insertInstance(e, true /* isRegex */)) { if (!error->empty()) *error += "\n"; *error += "Duplicated regex-instance '" + e + "' in " + intf->name(); success = false; } } return success; } }; HalInterfaceConverter halInterfaceConverter{}; struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> { std::string elementName() const override { return "hal"; } void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override { appendAttr(root, "format", hal.format); appendAttr(root, "optional", hal.optional); appendTextElement(root, "name", hal.name, d); appendChildren(root, versionRangeConverter, hal.versionRanges, d); appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d); } bool buildObject(MatrixHal* object, NodeType* root, std::string* error) const override { std::vector<HalInterface> interfaces; if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) || !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional, error) || !parseTextElement(root, "name", &object->name, error) || !parseChildren(root, versionRangeConverter, &object->versionRanges, error) || !parseChildren(root, halInterfaceConverter, &interfaces, error)) { return false; } for (auto&& interface : interfaces) { std::string name{interface.name()}; auto res = object->interfaces.emplace(std::move(name), std::move(interface)); if (!res.second) { *error = "Duplicated interface entry \"" + res.first->first + "\"; if additional instances are needed, add them to the " "existing <interface> node."; return false; } } // Do not check for target-side libvintf to avoid restricting ability for upgrade accidentally. #ifndef LIBVINTF_TARGET if (!checkAdditionalRestrictionsOnHal(*object, error)) { return false; } #endif return true; } #ifndef LIBVINTF_TARGET private: bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal, std::string* error) const { if (hal.getName() == "netutils-wrapper") { if (hal.versionRanges.size() != 1) { *error = "netutils-wrapper HAL must specify exactly one version x.0, " "but multiple <version> element is specified."; return false; } const VersionRange& v = hal.versionRanges.at(0); if (!v.isSingleVersion()) { *error = "netutils-wrapper HAL must specify exactly one version x.0, " "but a range is provided. Perhaps you mean '" + to_string(Version{v.majorVer, 0}) + "'?"; return false; } if (v.minMinor != 0) { *error = "netutils-wrapper HAL must specify exactly one version x.0, " "but minor version is not 0. Perhaps you mean '" + to_string(Version{v.majorVer, 0}) + "'?"; return false; } } return true; } #endif }; MatrixHalConverter matrixHalConverter{}; struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> { std::string elementName() const override { return "conditions"; } void mutateNode(const std::vector<KernelConfig>& conds, NodeType* root, DocType* d) const override { appendChildren(root, kernelConfigConverter, conds, d); } bool buildObject(std::vector<KernelConfig>* object, NodeType* root, std::string* error) const override { return parseChildren(root, kernelConfigConverter, object, error); } }; MatrixKernelConditionsConverter matrixKernelConditionsConverter{}; struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> { std::string elementName() const override { return "kernel"; } void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override { appendAttr(root, "version", kernel.mMinLts); if (!kernel.mConditions.empty()) { appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d)); } appendChildren(root, kernelConfigConverter, kernel.mConfigs, d); } bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override { if (!parseAttr(root, "version", &object->mMinLts, error) || !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions, error) || !parseChildren(root, kernelConfigConverter, &object->mConfigs, error)) { return false; } return true; } }; MatrixKernelConverter matrixKernelConverter{}; XmlTextConverter<FqInstance> fqInstanceConverter{"fqname"}; struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> { std::string elementName() const override { return "hal"; } void mutateNode(const ManifestHal& m, NodeType* root, DocType* d) const override { mutateNode(m, root, d, SerializeFlag::EVERYTHING); } void mutateNode(const ManifestHal& hal, NodeType* root, DocType* d, SerializeFlags flags) const override { appendAttr(root, "format", hal.format); appendTextElement(root, "name", hal.name, d); appendChild(root, transportArchConverter(hal.transportArch, d)); appendChildren(root, versionConverter, hal.versions, d); appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d); if (hal.isOverride()) { appendAttr(root, "override", hal.isOverride()); } if (!(flags & SerializeFlag::NO_FQNAME)) { std::set<FqInstance> fqInstances; hal.forEachInstance([&fqInstances](const auto& manifestInstance) { fqInstances.emplace(manifestInstance.getFqInstanceNoPackage()); return true; }); appendChildren(root, fqInstanceConverter, fqInstances, d); } } bool buildObject(ManifestHal* object, NodeType* root, std::string* error) const override { std::vector<HalInterface> interfaces; if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) || !parseOptionalAttr(root, "override", false, &object->mIsOverride, error) || !parseTextElement(root, "name", &object->name, error) || !parseOptionalChild(root, transportArchConverter, {}, &object->transportArch, error) || !parseChildren(root, versionConverter, &object->versions, error) || !parseChildren(root, halInterfaceConverter, &interfaces, error)) { return false; } switch (object->format) { case HalFormat::HIDL: { if (object->transportArch.empty()) { *error = "HIDL HAL '" + object->name + "' should have <transport> defined."; return false; } } break; case HalFormat::NATIVE: { if (!object->transportArch.empty()) { *error = "Native HAL '" + object->name + "' should not have <transport> defined."; return false; } } break; default: { LOG(FATAL) << "Unhandled HalFormat " << static_cast<typename std::underlying_type<HalFormat>::type>( object->format); } break; } if (!object->transportArch.isValid()) return false; object->interfaces.clear(); for (auto &&interface : interfaces) { auto res = object->interfaces.emplace(interface.name(), std::move(interface)); if (!res.second) { *error = "Duplicated interface entry \"" + res.first->first + "\"; if additional instances are needed, add them to the " "existing <interface> node."; return false; } } if (!object->isValid()) { *error = "'" + object->name + "' is not a valid Manifest HAL."; return false; } // Do not check for target-side libvintf to avoid restricting upgrade accidentally. #ifndef LIBVINTF_TARGET if (!checkAdditionalRestrictionsOnHal(*object, error)) { return false; } #endif std::set<FqInstance> fqInstances; if (!parseChildren(root, fqInstanceConverter, &fqInstances, error)) { return false; } if (!object->insertInstances(fqInstances, error)) { return false; } return true; } #ifndef LIBVINTF_TARGET private: bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal, std::string* error) const { if (hal.getName() == "netutils-wrapper") { for (const Version& v : hal.versions) { if (v.minorVer != 0) { *error = "netutils-wrapper HAL must specify exactly one version x.0, " "but minor version is not 0. Perhaps you mean '" + to_string(Version{v.majorVer, 0}) + "'?"; return false; } } } return true; } #endif }; // Convert ManifestHal from and to XML. Returned object is guaranteed to have // .isValid() == true. ManifestHalConverter manifestHalConverter{}; XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"}; XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"}; struct SepolicyConverter : public XmlNodeConverter<Sepolicy> { std::string elementName() const override { return "sepolicy"; } void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override { appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d)); appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d); } bool buildObject(Sepolicy* object, NodeType* root, std::string* error) const override { if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion, error) || !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges, error)) { return false; } return true; } }; SepolicyConverter sepolicyConverter{}; [[deprecated]] XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"}; XmlTextConverter<std::string> vndkVersionConverter{"version"}; XmlTextConverter<std::string> vndkLibraryConverter{"library"}; struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> { std::string elementName() const override { return "vndk"; } void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override { appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d)); appendChildren(root, vndkLibraryConverter, object.mLibraries, d); } bool buildObject(Vndk* object, NodeType* root, std::string* error) const override { if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange, error) || !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) { return false; } return true; } }; [[deprecated]] VndkConverter vndkConverter{}; struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> { std::string elementName() const override { return "vendor-ndk"; } void mutateNode(const VendorNdk& object, NodeType* root, DocType* d) const override { appendChild(root, vndkVersionConverter(object.mVersion, d)); appendChildren(root, vndkLibraryConverter, object.mLibraries, d); } bool buildObject(VendorNdk* object, NodeType* root, std::string* error) const override { if (!parseChild(root, vndkVersionConverter, &object->mVersion, error) || !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) { return false; } return true; } }; VendorNdkConverter vendorNdkConverter{}; XmlTextConverter<std::string> systemSdkVersionConverter{"version"}; struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> { std::string elementName() const override { return "system-sdk"; } void mutateNode(const SystemSdk& object, NodeType* root, DocType* d) const override { appendChildren(root, systemSdkVersionConverter, object.versions(), d); } bool buildObject(SystemSdk* object, NodeType* root, std::string* error) const override { return parseChildren(root, systemSdkVersionConverter, &object->mVersions, error); } }; SystemSdkConverter systemSdkConverter{}; struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> { std::string elementName() const override { return "sepolicy"; } void mutateNode(const Version &m, NodeType *root, DocType *d) const override { appendChild(root, versionConverter(m, d)); } bool buildObject(Version* object, NodeType* root, std::string* error) const override { return parseChild(root, versionConverter, object, error); } }; HalManifestSepolicyConverter halManifestSepolicyConverter{}; struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> { std::string elementName() const override { return "xmlfile"; } void mutateNode(const ManifestXmlFile& f, NodeType* root, DocType* d) const override { appendTextElement(root, "name", f.name(), d); appendChild(root, versionConverter(f.version(), d)); if (!f.overriddenPath().empty()) { appendTextElement(root, "path", f.overriddenPath(), d); } } bool buildObject(ManifestXmlFile* object, NodeType* root, std::string* error) const override { if (!parseTextElement(root, "name", &object->mName, error) || !parseChild(root, versionConverter, &object->mVersion, error) || !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) { return false; } return true; } }; ManifestXmlFileConverter manifestXmlFileConverter{}; struct HalManifestConverter : public XmlNodeConverter<HalManifest> { std::string elementName() const override { return "manifest"; } void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override { mutateNode(m, root, d, SerializeFlag::EVERYTHING); } void mutateNode(const HalManifest& m, NodeType* root, DocType* d, SerializeFlags flags) const override { appendAttr(root, "version", m.getMetaVersion()); appendAttr(root, "type", m.mType); if (!(flags & SerializeFlag::NO_HALS)) { appendChildren(root, manifestHalConverter, m.getHals(), d, flags); } if (m.mType == SchemaType::DEVICE) { if (!(flags & SerializeFlag::NO_SEPOLICY)) { appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d)); } if (m.mLevel != Level::UNSPECIFIED) { this->appendAttr(root, "target-level", m.mLevel); } } else if (m.mType == SchemaType::FRAMEWORK) { if (!(flags & SerializeFlag::NO_VNDK)) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" appendChildren(root, vndkConverter, m.framework.mVndks, d); #pragma clang diagnostic pop appendChildren(root, vendorNdkConverter, m.framework.mVendorNdks, d); } if (!(flags & SerializeFlag::NO_SSDK)) { if (!m.framework.mSystemSdk.empty()) { appendChild(root, systemSdkConverter(m.framework.mSystemSdk, d)); } } } if (!(flags & SerializeFlag::NO_XMLFILES)) { appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d); } } bool buildObject(HalManifest* object, NodeType* root, std::string* error) const override { std::vector<ManifestHal> hals; if (!parseAttr(root, "version", &object->mMetaVersion, error) || !parseAttr(root, "type", &object->mType, error) || !parseChildren(root, manifestHalConverter, &hals, error)) { return false; } if (!kMetaVersion.minorAtLeast(object->mMetaVersion)) { *error = "Unrecognized manifest.version " + to_string(object->mMetaVersion) + " (libvintf@" + to_string(kMetaVersion) + ")"; return false; } if (object->mType == SchemaType::DEVICE) { // tags for device hal manifest only. // <sepolicy> can be missing because it can be determined at build time, not hard-coded // in the XML file. if (!parseOptionalChild(root, halManifestSepolicyConverter, {}, &object->device.mSepolicyVersion, error)) { return false; } if (!parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel, error)) { return false; } } else if (object->mType == SchemaType::FRAMEWORK) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" if (!parseChildren(root, vndkConverter, &object->framework.mVndks, error)) { return false; } for (const auto &vndk : object->framework.mVndks) { if (!vndk.mVersionRange.isSingleVersion()) { *error = "vndk.version " + to_string(vndk.mVersionRange) + " cannot be a range for manifests"; return false; } } #pragma clang diagnostic pop if (!parseChildren(root, vendorNdkConverter, &object->framework.mVendorNdks, error)) { return false; } std::set<std::string> vendorNdkVersions; for (const auto& vendorNdk : object->framework.mVendorNdks) { if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) { *error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version(); return false; } vendorNdkVersions.insert(vendorNdk.version()); } if (!parseOptionalChild(root, systemSdkConverter, {}, &object->framework.mSystemSdk, error)) { return false; } } for (auto &&hal : hals) { std::string description{hal.name}; if (!object->add(std::move(hal))) { *error = "Duplicated manifest.hal entry " + description; return false; } } std::vector<ManifestXmlFile> xmlFiles; if (!parseChildren(root, manifestXmlFileConverter, &xmlFiles, error)) { return false; } for (auto&& xmlFile : xmlFiles) { std::string description{xmlFile.name()}; if (!object->addXmlFile(std::move(xmlFile))) { *error = "Duplicated manifest.xmlfile entry " + description + "; entries cannot have duplicated name and version"; return false; } } return true; } }; HalManifestConverter halManifestConverter{}; XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"}; struct AvbConverter : public XmlNodeConverter<Version> { std::string elementName() const override { return "avb"; } void mutateNode(const Version &m, NodeType *root, DocType *d) const override { appendChild(root, avbVersionConverter(m, d)); } bool buildObject(Version* object, NodeType* root, std::string* error) const override { return parseChild(root, avbVersionConverter, object, error); } }; AvbConverter avbConverter{}; struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> { std::string elementName() const override { return "xmlfile"; } void mutateNode(const MatrixXmlFile& f, NodeType* root, DocType* d) const override { appendTextElement(root, "name", f.name(), d); appendAttr(root, "format", f.format()); appendAttr(root, "optional", f.optional()); appendChild(root, versionRangeConverter(f.versionRange(), d)); if (!f.overriddenPath().empty()) { appendTextElement(root, "path", f.overriddenPath(), d); } } bool buildObject(MatrixXmlFile* object, NodeType* root, std::string* error) const override { if (!parseTextElement(root, "name", &object->mName, error) || !parseAttr(root, "format", &object->mFormat, error) || !parseOptionalAttr(root, "optional", false, &object->mOptional, error) || !parseChild(root, versionRangeConverter, &object->mVersionRange, error) || !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) { return false; } return true; } }; MatrixXmlFileConverter matrixXmlFileConverter{}; struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> { std::string elementName() const override { return "compatibility-matrix"; } void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override { mutateNode(m, root, d, SerializeFlag::EVERYTHING); } void mutateNode(const CompatibilityMatrix& m, NodeType* root, DocType* d, SerializeFlags flags) const override { appendAttr(root, "version", m.getMinimumMetaVersion()); appendAttr(root, "type", m.mType); if (!(flags & SerializeFlag::NO_HALS)) { appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d); } if (m.mType == SchemaType::FRAMEWORK) { if (!(flags & SerializeFlag::NO_KERNEL)) { appendChildren(root, matrixKernelConverter, m.framework.mKernels, d); } if (!(flags & SerializeFlag::NO_SEPOLICY)) { if (!(m.framework.mSepolicy == Sepolicy{})) { appendChild(root, sepolicyConverter(m.framework.mSepolicy, d)); } } if (!(flags & SerializeFlag::NO_AVB)) { if (!(m.framework.mAvbMetaVersion == Version{})) { appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d)); } } if (m.mLevel != Level::UNSPECIFIED) { this->appendAttr(root, "level", m.mLevel); } } else if (m.mType == SchemaType::DEVICE) { if (!(flags & SerializeFlag::NO_VNDK)) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" if (!(m.device.mVndk == Vndk{})) { appendChild(root, vndkConverter(m.device.mVndk, d)); } #pragma clang diagnostic pop if (!(m.device.mVendorNdk == VendorNdk{})) { appendChild(root, vendorNdkConverter(m.device.mVendorNdk, d)); } } if (!(flags & SerializeFlag::NO_SSDK)) { if (!m.device.mSystemSdk.empty()) { appendChild(root, systemSdkConverter(m.device.mSystemSdk, d)); } } } if (!(flags & SerializeFlag::NO_XMLFILES)) { appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d); } } bool buildObject(CompatibilityMatrix* object, NodeType* root, std::string* error) const override { Version version; std::vector<MatrixHal> hals; if (!parseAttr(root, "version", &version, error) || !parseAttr(root, "type", &object->mType, error) || !parseChildren(root, matrixHalConverter, &hals, error)) { return false; } if (object->mType == SchemaType::FRAMEWORK) { // <avb> and <sepolicy> can be missing because it can be determined at build time, not // hard-coded in the XML file. if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels, error) || !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy, error) || !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion, error)) { return false; } std::set<Version> seenKernelVersions; for (const auto& kernel : object->framework.mKernels) { Version minLts(kernel.minLts().version, kernel.minLts().majorRev); if (seenKernelVersions.find(minLts) != seenKernelVersions.end()) { continue; } if (!kernel.conditions().empty()) { *error = "First <kernel> for version " + to_string(minLts) + " must have empty <conditions> for backwards compatibility."; return false; } seenKernelVersions.insert(minLts); } if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel, error)) { return false; } } else if (object->mType == SchemaType::DEVICE) { // <vndk> can be missing because it can be determined at build time, not hard-coded // in the XML file. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk, error)) { return false; } #pragma clang diagnostic pop if (!parseOptionalChild(root, vendorNdkConverter, {}, &object->device.mVendorNdk, error)) { return false; } if (!parseOptionalChild(root, systemSdkConverter, {}, &object->device.mSystemSdk, error)) { return false; } } if (!kMetaVersion.minorAtLeast(version)) { *error = "Unrecognized compatibility-matrix.version " + to_string(version) + " (libvintf@" + to_string(kMetaVersion) + ")"; return false; } for (auto &&hal : hals) { if (!object->add(std::move(hal))) { *error = "Duplicated compatibility-matrix.hal entry"; return false; } } std::vector<MatrixXmlFile> xmlFiles; if (!parseChildren(root, matrixXmlFileConverter, &xmlFiles, error)) { return false; } for (auto&& xmlFile : xmlFiles) { if (!xmlFile.optional()) { *error = "compatibility-matrix.xmlfile entry " + xmlFile.name() + " has to be optional for compatibility matrix version 1.0"; return false; } std::string description{xmlFile.name()}; if (!object->addXmlFile(std::move(xmlFile))) { *error = "Duplicated compatibility-matrix.xmlfile entry " + description; return false; } } return true; } }; CompatibilityMatrixConverter compatibilityMatrixConverter{}; // Publicly available as in parse_xml.h XmlConverter<HalManifest>& gHalManifestConverter = halManifestConverter; XmlConverter<CompatibilityMatrix>& gCompatibilityMatrixConverter = compatibilityMatrixConverter; // For testing in LibVintfTest XmlConverter<Version>& gVersionConverter = versionConverter; XmlConverter<KernelConfigTypedValue>& gKernelConfigTypedValueConverter = kernelConfigTypedValueConverter; XmlConverter<MatrixHal>& gMatrixHalConverter = matrixHalConverter; XmlConverter<ManifestHal>& gManifestHalConverter = manifestHalConverter; } // namespace vintf } // namespace android