Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 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 | |
Yifan Hong | e0bb98d | 2017-08-07 14:40:19 -0700 | [diff] [blame] | 19 | #define LOG_TAG "libvintf" |
| 20 | #include <android-base/logging.h> |
| 21 | |
| 22 | #include "parse_xml.h" |
| 23 | |
| 24 | #include <type_traits> |
| 25 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 26 | #include <tinyxml2.h> |
| 27 | |
Yifan Hong | 705216b | 2018-03-21 17:27:47 -0700 | [diff] [blame] | 28 | #include "Regex.h" |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 29 | #include "constants-private.h" |
Yifan Hong | db127cb | 2017-09-19 13:36:21 -0700 | [diff] [blame] | 30 | #include "constants.h" |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 31 | #include "parse_string.h" |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 32 | |
| 33 | namespace android { |
| 34 | namespace vintf { |
| 35 | |
| 36 | // --------------- tinyxml2 details |
| 37 | |
| 38 | using NodeType = tinyxml2::XMLElement; |
| 39 | using DocType = tinyxml2::XMLDocument; |
| 40 | |
| 41 | // caller is responsible for deleteDocument() call |
| 42 | inline DocType *createDocument() { |
| 43 | return new tinyxml2::XMLDocument(); |
| 44 | } |
| 45 | |
| 46 | // caller is responsible for deleteDocument() call |
| 47 | inline DocType *createDocument(const std::string &xml) { |
| 48 | DocType *doc = new tinyxml2::XMLDocument(); |
Elliott Hughes | a4c0a2e | 2017-08-08 11:26:24 -0700 | [diff] [blame] | 49 | if (doc->Parse(xml.c_str()) == tinyxml2::XML_SUCCESS) { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 50 | return doc; |
| 51 | } |
| 52 | delete doc; |
| 53 | return nullptr; |
| 54 | } |
| 55 | |
| 56 | inline void deleteDocument(DocType *d) { |
| 57 | delete d; |
| 58 | } |
| 59 | |
| 60 | inline std::string printDocument(DocType *d) { |
| 61 | tinyxml2::XMLPrinter p; |
| 62 | d->Print(&p); |
| 63 | return std::string{p.CStr()}; |
| 64 | } |
| 65 | |
| 66 | inline NodeType *createNode(const std::string &name, DocType *d) { |
| 67 | return d->NewElement(name.c_str()); |
| 68 | } |
| 69 | |
| 70 | inline void appendChild(NodeType *parent, NodeType *child) { |
| 71 | parent->InsertEndChild(child); |
| 72 | } |
| 73 | |
| 74 | inline void appendChild(DocType *parent, NodeType *child) { |
| 75 | parent->InsertEndChild(child); |
| 76 | } |
| 77 | |
| 78 | inline void appendStrAttr(NodeType *e, const std::string &attrName, const std::string &attr) { |
| 79 | e->SetAttribute(attrName.c_str(), attr.c_str()); |
| 80 | } |
| 81 | |
| 82 | // text -> text |
| 83 | inline void appendText(NodeType *parent, const std::string &text, DocType *d) { |
| 84 | parent->InsertEndChild(d->NewText(text.c_str())); |
| 85 | } |
| 86 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 87 | inline std::string nameOf(NodeType *root) { |
Yifan Hong | cd41ffc | 2017-01-20 13:46:32 -0800 | [diff] [blame] | 88 | return root->Name() == NULL ? "" : root->Name(); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | inline std::string getText(NodeType *root) { |
Yifan Hong | cd41ffc | 2017-01-20 13:46:32 -0800 | [diff] [blame] | 92 | return root->GetText() == NULL ? "" : root->GetText(); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | inline NodeType *getChild(NodeType *parent, const std::string &name) { |
| 96 | return parent->FirstChildElement(name.c_str()); |
| 97 | } |
| 98 | |
| 99 | inline NodeType *getRootChild(DocType *parent) { |
| 100 | return parent->FirstChildElement(); |
| 101 | } |
| 102 | |
| 103 | inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) { |
| 104 | std::vector<NodeType *> v; |
| 105 | for (NodeType *child = parent->FirstChildElement(name.c_str()); |
| 106 | child != nullptr; |
| 107 | child = child->NextSiblingElement(name.c_str())) { |
| 108 | v.push_back(child); |
| 109 | } |
| 110 | return v; |
| 111 | } |
| 112 | |
| 113 | inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) { |
| 114 | const char *c = root->Attribute(attrName.c_str()); |
| 115 | if (c == NULL) |
| 116 | return false; |
| 117 | *s = c; |
| 118 | return true; |
| 119 | } |
| 120 | |
| 121 | // --------------- tinyxml2 details end. |
| 122 | |
Yifan Hong | 8e9c669 | 2017-02-28 14:07:42 -0800 | [diff] [blame] | 123 | // Helper functions for XmlConverter |
| 124 | static bool parse(const std::string &attrText, bool *attr) { |
| 125 | if (attrText == "true" || attrText == "1") { |
| 126 | *attr = true; |
| 127 | return true; |
| 128 | } |
| 129 | if (attrText == "false" || attrText == "0") { |
| 130 | *attr = false; |
| 131 | return true; |
| 132 | } |
| 133 | return false; |
| 134 | } |
| 135 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 136 | // ---------------------- XmlNodeConverter definitions |
| 137 | |
| 138 | template<typename Object> |
| 139 | struct XmlNodeConverter : public XmlConverter<Object> { |
| 140 | XmlNodeConverter() {} |
| 141 | virtual ~XmlNodeConverter() {} |
| 142 | |
| 143 | // sub-types should implement these. |
| 144 | virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0; |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 145 | virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags::Type) const { |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 146 | mutateNode(o, n, d); |
| 147 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 148 | virtual bool buildObject(Object* o, NodeType* n, std::string* error) const = 0; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 149 | virtual std::string elementName() const = 0; |
| 150 | |
| 151 | // convenience methods for user |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 152 | inline const std::string& lastError() const override { return mLastError; } |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 153 | inline NodeType* serialize(const Object& o, DocType* d, |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 154 | SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 155 | NodeType *root = createNode(this->elementName(), d); |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 156 | this->mutateNode(o, root, d, flags); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 157 | return root; |
| 158 | } |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 159 | inline std::string serialize(const Object& o, SerializeFlags::Type flags) const override { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 160 | DocType *doc = createDocument(); |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 161 | appendChild(doc, serialize(o, doc, flags)); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 162 | std::string s = printDocument(doc); |
| 163 | deleteDocument(doc); |
| 164 | return s; |
| 165 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 166 | inline bool deserialize(Object* object, NodeType* root) { |
| 167 | bool ret = deserialize(object, root, &mLastError); |
| 168 | return ret; |
| 169 | } |
| 170 | inline bool deserialize(Object* o, const std::string& xml) override { |
| 171 | bool ret = (*this)(o, xml, &mLastError); |
| 172 | return ret; |
| 173 | } |
| 174 | inline bool deserialize(Object* object, NodeType* root, std::string* error) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 175 | if (nameOf(root) != this->elementName()) { |
| 176 | return false; |
| 177 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 178 | return this->buildObject(object, root, error); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 179 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 180 | inline bool operator()(Object* o, const std::string& xml, std::string* error) const override { |
| 181 | std::string errorBuffer; |
| 182 | if (error == nullptr) error = &errorBuffer; |
| 183 | |
| 184 | auto doc = createDocument(xml); |
Yifan Hong | 08e984c | 2017-05-18 12:50:04 -0700 | [diff] [blame] | 185 | if (doc == nullptr) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 186 | *error = "Not a valid XML"; |
Yifan Hong | 08e984c | 2017-05-18 12:50:04 -0700 | [diff] [blame] | 187 | return false; |
| 188 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 189 | bool ret = deserialize(o, getRootChild(doc), error); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 190 | deleteDocument(doc); |
| 191 | return ret; |
| 192 | } |
| 193 | inline NodeType *operator()(const Object &o, DocType *d) const { |
| 194 | return serialize(o, d); |
| 195 | } |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 196 | inline std::string operator()(const Object& o, SerializeFlags::Type flags) const override { |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 197 | return serialize(o, flags); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 198 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 199 | inline bool operator()(Object* o, NodeType* node) { return deserialize(o, node); } |
| 200 | inline bool operator()(Object* o, const std::string& xml) override { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 201 | return deserialize(o, xml); |
| 202 | } |
| 203 | |
| 204 | // convenience methods for implementor. |
Yifan Hong | 8e9c669 | 2017-02-28 14:07:42 -0800 | [diff] [blame] | 205 | |
| 206 | // All append* functions helps mutateNode() to serialize the object into XML. |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 207 | template <typename T> |
| 208 | inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const { |
| 209 | return appendStrAttr(e, attrName, ::android::vintf::to_string(attr)); |
| 210 | } |
| 211 | |
| 212 | inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const { |
| 213 | return appendStrAttr(e, attrName, attr ? "true" : "false"); |
| 214 | } |
| 215 | |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 216 | // text -> <name>text</name> |
| 217 | inline void appendTextElement(NodeType *parent, const std::string &name, |
| 218 | const std::string &text, DocType *d) const { |
| 219 | NodeType *c = createNode(name, d); |
| 220 | appendText(c, text, d); |
| 221 | appendChild(parent, c); |
| 222 | } |
| 223 | |
| 224 | // text -> <name>text</name> |
| 225 | template<typename Array> |
| 226 | inline void appendTextElements(NodeType *parent, const std::string &name, |
| 227 | const Array &array, DocType *d) const { |
| 228 | for (const std::string &text : array) { |
| 229 | NodeType *c = createNode(name, d); |
| 230 | appendText(c, text, d); |
| 231 | appendChild(parent, c); |
| 232 | } |
| 233 | } |
| 234 | |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 235 | template <typename T, typename Array> |
| 236 | inline void appendChildren(NodeType* parent, const XmlNodeConverter<T>& conv, |
| 237 | const Array& array, DocType* d, |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 238 | SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const { |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 239 | for (const T &t : array) { |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 240 | appendChild(parent, conv.serialize(t, d, flags)); |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 241 | } |
| 242 | } |
| 243 | |
Yifan Hong | 8e9c669 | 2017-02-28 14:07:42 -0800 | [diff] [blame] | 244 | // All parse* functions helps buildObject() to deserialize XML to the object. Returns |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 245 | // true if deserialization is successful, false if any error, and "error" will be |
Yifan Hong | 8e9c669 | 2017-02-28 14:07:42 -0800 | [diff] [blame] | 246 | // set to error message. |
| 247 | template <typename T> |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 248 | inline bool parseOptionalAttr(NodeType* root, const std::string& attrName, T&& defaultValue, |
| 249 | T* attr, std::string* /* error */) const { |
Yifan Hong | 8e9c669 | 2017-02-28 14:07:42 -0800 | [diff] [blame] | 250 | std::string attrText; |
| 251 | bool success = getAttr(root, attrName, &attrText) && |
| 252 | ::android::vintf::parse(attrText, attr); |
| 253 | if (!success) { |
| 254 | *attr = std::move(defaultValue); |
| 255 | } |
| 256 | return true; |
| 257 | } |
| 258 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 259 | template <typename T> |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 260 | inline bool parseAttr(NodeType* root, const std::string& attrName, T* attr, |
| 261 | std::string* error) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 262 | std::string attrText; |
| 263 | bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr); |
| 264 | if (!ret) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 265 | *error = "Could not find/parse attr with name \"" + attrName + "\" and value \"" + |
| 266 | attrText + "\" for element <" + elementName() + ">"; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 267 | } |
| 268 | return ret; |
| 269 | } |
| 270 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 271 | inline bool parseAttr(NodeType* root, const std::string& attrName, std::string* attr, |
| 272 | std::string* error) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 273 | bool ret = getAttr(root, attrName, attr); |
| 274 | if (!ret) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 275 | *error = "Could not find attr with name \"" + attrName + "\" for element <" + |
| 276 | elementName() + ">"; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 277 | } |
| 278 | return ret; |
| 279 | } |
| 280 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 281 | inline bool parseTextElement(NodeType* root, const std::string& elementName, std::string* s, |
| 282 | std::string* error) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 283 | NodeType *child = getChild(root, elementName); |
| 284 | if (child == nullptr) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 285 | *error = "Could not find element with name <" + elementName + "> in element <" + |
| 286 | this->elementName() + ">"; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 287 | return false; |
| 288 | } |
| 289 | *s = getText(child); |
| 290 | return true; |
| 291 | } |
| 292 | |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 293 | inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName, |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 294 | std::string&& defaultValue, std::string* s, |
| 295 | std::string* /* error */) const { |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 296 | NodeType* child = getChild(root, elementName); |
| 297 | *s = child == nullptr ? std::move(defaultValue) : getText(child); |
| 298 | return true; |
| 299 | } |
| 300 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 301 | inline bool parseTextElements(NodeType* root, const std::string& elementName, |
| 302 | std::vector<std::string>* v, std::string* /* error */) const { |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 303 | auto nodes = getChildren(root, elementName); |
| 304 | v->resize(nodes.size()); |
| 305 | for (size_t i = 0; i < nodes.size(); ++i) { |
| 306 | v->at(i) = getText(nodes[i]); |
| 307 | } |
| 308 | return true; |
| 309 | } |
| 310 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 311 | template <typename T> |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 312 | inline bool parseChild(NodeType* root, const XmlNodeConverter<T>& conv, T* t, |
| 313 | std::string* error) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 314 | NodeType *child = getChild(root, conv.elementName()); |
| 315 | if (child == nullptr) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 316 | *error = "Could not find element with name <" + conv.elementName() + "> in element <" + |
| 317 | this->elementName() + ">"; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 318 | return false; |
| 319 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 320 | return conv.deserialize(t, child, error); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 321 | } |
| 322 | |
| 323 | template <typename T> |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 324 | inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv, |
| 325 | T&& defaultValue, T* t, std::string* error) const { |
Yifan Hong | 8e9c669 | 2017-02-28 14:07:42 -0800 | [diff] [blame] | 326 | NodeType *child = getChild(root, conv.elementName()); |
| 327 | if (child == nullptr) { |
| 328 | *t = std::move(defaultValue); |
| 329 | return true; |
| 330 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 331 | return conv.deserialize(t, child, error); |
Yifan Hong | 8e9c669 | 2017-02-28 14:07:42 -0800 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | template <typename T> |
Yifan Hong | a45f77d | 2018-12-03 16:42:52 -0800 | [diff] [blame] | 335 | inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv, |
| 336 | std::optional<T>* t, std::string* error) const { |
| 337 | NodeType* child = getChild(root, conv.elementName()); |
| 338 | if (child == nullptr) { |
| 339 | *t = std::nullopt; |
| 340 | return true; |
| 341 | } |
| 342 | *t = std::make_optional<T>(); |
| 343 | return conv.deserialize(&**t, child, error); |
| 344 | } |
| 345 | |
| 346 | template <typename T> |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 347 | inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v, |
| 348 | std::string* error) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 349 | auto nodes = getChildren(root, conv.elementName()); |
| 350 | v->resize(nodes.size()); |
| 351 | for (size_t i = 0; i < nodes.size(); ++i) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 352 | if (!conv.deserialize(&v->at(i), nodes[i], error)) { |
| 353 | *error = "Could not parse element with name <" + conv.elementName() + |
| 354 | "> in element <" + this->elementName() + ">: " + *error; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 355 | return false; |
| 356 | } |
| 357 | } |
| 358 | return true; |
| 359 | } |
| 360 | |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 361 | template <typename Container, typename T = typename Container::value_type, |
| 362 | typename = typename Container::key_compare> |
| 363 | inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, Container* s, |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 364 | std::string* error) const { |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 365 | std::vector<T> vec; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 366 | if (!parseChildren(root, conv, &vec, error)) { |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 367 | return false; |
| 368 | } |
| 369 | s->clear(); |
| 370 | s->insert(vec.begin(), vec.end()); |
| 371 | if (s->size() != vec.size()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 372 | *error = "Duplicated elements <" + conv.elementName() + "> in element <" + |
| 373 | this->elementName() + ">"; |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 374 | s->clear(); |
| 375 | return false; |
| 376 | } |
| 377 | return true; |
| 378 | } |
| 379 | |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 380 | template <typename K, typename V> |
| 381 | inline bool parseChildren(NodeType* root, const XmlNodeConverter<std::pair<K, V>>& conv, |
| 382 | std::map<K, V>* s, std::string* error) const { |
| 383 | return parseChildren<std::map<K, V>, std::pair<K, V>>(root, conv, s, error); |
| 384 | } |
| 385 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 386 | inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 387 | *s = getText(node); |
| 388 | return true; |
| 389 | } |
| 390 | |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 391 | template <typename T> |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 392 | inline bool parseText(NodeType* node, T* s, std::string* error) const { |
Yifan Hong | c6771f2 | 2017-04-05 11:45:18 -0700 | [diff] [blame] | 393 | std::string text = getText(node); |
| 394 | bool ret = ::android::vintf::parse(text, s); |
| 395 | if (!ret) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 396 | *error = "Could not parse text \"" + text + "\" in element <" + elementName() + ">"; |
Yifan Hong | c6771f2 | 2017-04-05 11:45:18 -0700 | [diff] [blame] | 397 | } |
| 398 | return ret; |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 399 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 400 | |
| 401 | private: |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 402 | mutable std::string mLastError; |
| 403 | }; |
| 404 | |
| 405 | template<typename Object> |
| 406 | struct XmlTextConverter : public XmlNodeConverter<Object> { |
| 407 | XmlTextConverter(const std::string &elementName) |
| 408 | : mElementName(elementName) {} |
| 409 | |
| 410 | virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override { |
| 411 | appendText(root, ::android::vintf::to_string(object), d); |
| 412 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 413 | virtual bool buildObject(Object* object, NodeType* root, std::string* error) const override { |
| 414 | return this->parseText(root, object, error); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 415 | } |
Yifan Hong | 832e390 | 2018-07-16 15:22:55 -0700 | [diff] [blame] | 416 | virtual std::string elementName() const { return mElementName; } |
| 417 | |
| 418 | private: |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 419 | std::string mElementName; |
| 420 | }; |
| 421 | |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 422 | template <typename Pair> |
| 423 | struct XmlPairConverter : public XmlNodeConverter<Pair> { |
| 424 | XmlPairConverter( |
| 425 | const std::string& elementName, |
| 426 | std::unique_ptr<XmlNodeConverter<typename Pair::first_type>>&& firstConverter, |
| 427 | std::unique_ptr<XmlNodeConverter<typename Pair::second_type>>&& secondConverter) |
| 428 | : mElementName(elementName), |
| 429 | mFirstConverter(std::move(firstConverter)), |
| 430 | mSecondConverter(std::move(secondConverter)) {} |
| 431 | |
| 432 | virtual void mutateNode(const Pair& pair, NodeType* root, DocType* d) const override { |
| 433 | appendChild(root, mFirstConverter->serialize(pair.first, d)); |
| 434 | appendChild(root, mSecondConverter->serialize(pair.second, d)); |
| 435 | } |
| 436 | virtual bool buildObject(Pair* pair, NodeType* root, std::string* error) const override { |
| 437 | return this->parseChild(root, *mFirstConverter, &pair->first, error) && |
| 438 | this->parseChild(root, *mSecondConverter, &pair->second, error); |
| 439 | } |
| 440 | virtual std::string elementName() const { return mElementName; } |
| 441 | |
| 442 | private: |
| 443 | std::string mElementName; |
| 444 | std::unique_ptr<XmlNodeConverter<typename Pair::first_type>> mFirstConverter; |
| 445 | std::unique_ptr<XmlNodeConverter<typename Pair::second_type>> mSecondConverter; |
| 446 | }; |
| 447 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 448 | // ---------------------- XmlNodeConverter definitions end |
| 449 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 450 | XmlTextConverter<Version> versionConverter{"version"}; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 451 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 452 | XmlTextConverter<VersionRange> versionRangeConverter{"version"}; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 453 | |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 454 | struct TransportArchConverter : public XmlNodeConverter<TransportArch> { |
| 455 | std::string elementName() const override { return "transport"; } |
| 456 | void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override { |
| 457 | if (object.arch != Arch::ARCH_EMPTY) { |
| 458 | appendAttr(root, "arch", object.arch); |
| 459 | } |
| 460 | appendText(root, ::android::vintf::to_string(object.transport), d); |
| 461 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 462 | bool buildObject(TransportArch* object, NodeType* root, std::string* error) const override { |
| 463 | if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, error) || |
| 464 | !parseText(root, &object->transport, error)) { |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 465 | return false; |
| 466 | } |
| 467 | if (!object->isValid()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 468 | *error = "transport == " + ::android::vintf::to_string(object->transport) + |
| 469 | " and arch == " + ::android::vintf::to_string(object->arch) + |
| 470 | " is not a valid combination."; |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 471 | return false; |
| 472 | } |
| 473 | return true; |
| 474 | } |
| 475 | }; |
| 476 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 477 | TransportArchConverter transportArchConverter{}; |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 478 | |
Yifan Hong | 3f5489a | 2017-02-08 11:14:21 -0800 | [diff] [blame] | 479 | struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> { |
| 480 | std::string elementName() const override { return "value"; } |
| 481 | void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override { |
| 482 | appendAttr(root, "type", object.mType); |
| 483 | appendText(root, ::android::vintf::to_string(object), d); |
| 484 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 485 | bool buildObject(KernelConfigTypedValue* object, NodeType* root, |
| 486 | std::string* error) const override { |
Yifan Hong | 3f5489a | 2017-02-08 11:14:21 -0800 | [diff] [blame] | 487 | std::string stringValue; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 488 | if (!parseAttr(root, "type", &object->mType, error) || |
| 489 | !parseText(root, &stringValue, error)) { |
Yifan Hong | 3f5489a | 2017-02-08 11:14:21 -0800 | [diff] [blame] | 490 | return false; |
| 491 | } |
| 492 | if (!::android::vintf::parseKernelConfigValue(stringValue, object)) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 493 | *error = "Could not parse kernel config value \"" + stringValue + "\""; |
Yifan Hong | 3f5489a | 2017-02-08 11:14:21 -0800 | [diff] [blame] | 494 | return false; |
| 495 | } |
| 496 | return true; |
| 497 | } |
| 498 | }; |
| 499 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 500 | KernelConfigTypedValueConverter kernelConfigTypedValueConverter{}; |
Yifan Hong | 3f5489a | 2017-02-08 11:14:21 -0800 | [diff] [blame] | 501 | |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 502 | XmlPairConverter<KernelConfig> matrixKernelConfigConverter{ |
| 503 | "config", std::make_unique<XmlTextConverter<KernelConfigKey>>("key"), |
| 504 | std::make_unique<KernelConfigTypedValueConverter>(kernelConfigTypedValueConverter)}; |
Yifan Hong | 3f5489a | 2017-02-08 11:14:21 -0800 | [diff] [blame] | 505 | |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 506 | struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> { |
| 507 | std::string elementName() const override { return "interface"; } |
| 508 | void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override { |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 509 | appendTextElement(root, "name", intf.name(), d); |
| 510 | appendTextElements(root, "instance", intf.mInstances, d); |
Yifan Hong | 705216b | 2018-03-21 17:27:47 -0700 | [diff] [blame] | 511 | appendTextElements(root, "regex-instance", intf.mRegexes, d); |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 512 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 513 | bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override { |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 514 | std::vector<std::string> instances; |
Yifan Hong | 705216b | 2018-03-21 17:27:47 -0700 | [diff] [blame] | 515 | std::vector<std::string> regexes; |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 516 | if (!parseTextElement(root, "name", &intf->mName, error) || |
Yifan Hong | 705216b | 2018-03-21 17:27:47 -0700 | [diff] [blame] | 517 | !parseTextElements(root, "instance", &instances, error) || |
| 518 | !parseTextElements(root, "regex-instance", ®exes, error)) { |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 519 | return false; |
| 520 | } |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 521 | bool success = true; |
| 522 | for (const auto& e : instances) { |
| 523 | if (!intf->insertInstance(e, false /* isRegex */)) { |
| 524 | if (!error->empty()) *error += "\n"; |
| 525 | *error += "Duplicated instance '" + e + "' in " + intf->name(); |
| 526 | success = false; |
| 527 | } |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 528 | } |
Yifan Hong | 705216b | 2018-03-21 17:27:47 -0700 | [diff] [blame] | 529 | for (const auto& e : regexes) { |
| 530 | details::Regex regex; |
| 531 | if (!regex.compile(e)) { |
| 532 | if (!error->empty()) *error += "\n"; |
| 533 | *error += "Invalid regular expression '" + e + "' in " + intf->name(); |
| 534 | success = false; |
| 535 | } |
| 536 | if (!intf->insertInstance(e, true /* isRegex */)) { |
| 537 | if (!error->empty()) *error += "\n"; |
| 538 | *error += "Duplicated regex-instance '" + e + "' in " + intf->name(); |
| 539 | success = false; |
| 540 | } |
| 541 | } |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 542 | return success; |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 543 | } |
| 544 | }; |
| 545 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 546 | HalInterfaceConverter halInterfaceConverter{}; |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 547 | |
Yifan Hong | a999357 | 2017-01-24 19:33:15 -0800 | [diff] [blame] | 548 | struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 549 | std::string elementName() const override { return "hal"; } |
| 550 | void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override { |
| 551 | appendAttr(root, "format", hal.format); |
| 552 | appendAttr(root, "optional", hal.optional); |
| 553 | appendTextElement(root, "name", hal.name, d); |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 554 | // Don't write <version> for format="aidl" |
| 555 | if (hal.format != HalFormat::AIDL) { |
| 556 | appendChildren(root, versionRangeConverter, hal.versionRanges, d); |
| 557 | } |
Yifan Hong | 9cd9eb0 | 2017-05-17 18:36:08 -0700 | [diff] [blame] | 558 | appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 559 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 560 | bool buildObject(MatrixHal* object, NodeType* root, std::string* error) const override { |
Yifan Hong | 9cd9eb0 | 2017-05-17 18:36:08 -0700 | [diff] [blame] | 561 | std::vector<HalInterface> interfaces; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 562 | if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) || |
| 563 | !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional, |
| 564 | error) || |
| 565 | !parseTextElement(root, "name", &object->name, error) || |
| 566 | !parseChildren(root, versionRangeConverter, &object->versionRanges, error) || |
| 567 | !parseChildren(root, halInterfaceConverter, &interfaces, error)) { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 568 | return false; |
| 569 | } |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 570 | if (object->format == HalFormat::AIDL) { |
| 571 | if (!object->versionRanges.empty()) { |
| 572 | LOG(WARNING) << "Ignoring <version> on matrix <hal format=\"aidl\"> " |
| 573 | << object->name; |
| 574 | object->versionRanges.clear(); |
| 575 | } |
| 576 | // Insert fake version for AIDL HALs so that compatibility check for AIDL and other |
| 577 | // HAL formats can be unified. |
| 578 | object->versionRanges.push_back(details::kFakeAidlVersionRange); |
| 579 | } |
Yifan Hong | 9cd9eb0 | 2017-05-17 18:36:08 -0700 | [diff] [blame] | 580 | for (auto&& interface : interfaces) { |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 581 | std::string name{interface.name()}; |
Yifan Hong | 9cd9eb0 | 2017-05-17 18:36:08 -0700 | [diff] [blame] | 582 | auto res = object->interfaces.emplace(std::move(name), std::move(interface)); |
| 583 | if (!res.second) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 584 | *error = "Duplicated interface entry \"" + res.first->first + |
| 585 | "\"; if additional instances are needed, add them to the " |
| 586 | "existing <interface> node."; |
Yifan Hong | 9cd9eb0 | 2017-05-17 18:36:08 -0700 | [diff] [blame] | 587 | return false; |
| 588 | } |
| 589 | } |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 590 | // Do not check for target-side libvintf to avoid restricting ability for upgrade accidentally. |
Yifan Hong | 6bce1a6 | 2018-01-31 13:30:04 -0800 | [diff] [blame] | 591 | #ifndef LIBVINTF_TARGET |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 592 | if (!checkAdditionalRestrictionsOnHal(*object, error)) { |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 593 | return false; |
| 594 | } |
| 595 | #endif |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 596 | return true; |
| 597 | } |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 598 | |
Yifan Hong | 6bce1a6 | 2018-01-31 13:30:04 -0800 | [diff] [blame] | 599 | #ifndef LIBVINTF_TARGET |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 600 | private: |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 601 | bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal, std::string* error) const { |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 602 | if (hal.getName() == "netutils-wrapper") { |
| 603 | if (hal.versionRanges.size() != 1) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 604 | *error = |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 605 | "netutils-wrapper HAL must specify exactly one version x.0, " |
| 606 | "but multiple <version> element is specified."; |
| 607 | return false; |
| 608 | } |
| 609 | const VersionRange& v = hal.versionRanges.at(0); |
| 610 | if (!v.isSingleVersion()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 611 | *error = |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 612 | "netutils-wrapper HAL must specify exactly one version x.0, " |
| 613 | "but a range is provided. Perhaps you mean '" + |
| 614 | to_string(Version{v.majorVer, 0}) + "'?"; |
| 615 | return false; |
| 616 | } |
| 617 | if (v.minMinor != 0) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 618 | *error = |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 619 | "netutils-wrapper HAL must specify exactly one version x.0, " |
| 620 | "but minor version is not 0. Perhaps you mean '" + |
| 621 | to_string(Version{v.majorVer, 0}) + "'?"; |
| 622 | return false; |
| 623 | } |
| 624 | } |
| 625 | return true; |
| 626 | } |
| 627 | #endif |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 628 | }; |
| 629 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 630 | MatrixHalConverter matrixHalConverter{}; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 631 | |
Yifan Hong | ff0a563 | 2017-08-21 18:39:29 -0700 | [diff] [blame] | 632 | struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> { |
| 633 | std::string elementName() const override { return "conditions"; } |
| 634 | void mutateNode(const std::vector<KernelConfig>& conds, NodeType* root, |
| 635 | DocType* d) const override { |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 636 | appendChildren(root, matrixKernelConfigConverter, conds, d); |
Yifan Hong | ff0a563 | 2017-08-21 18:39:29 -0700 | [diff] [blame] | 637 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 638 | bool buildObject(std::vector<KernelConfig>* object, NodeType* root, |
| 639 | std::string* error) const override { |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 640 | return parseChildren(root, matrixKernelConfigConverter, object, error); |
Yifan Hong | ff0a563 | 2017-08-21 18:39:29 -0700 | [diff] [blame] | 641 | } |
| 642 | }; |
| 643 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 644 | MatrixKernelConditionsConverter matrixKernelConditionsConverter{}; |
Yifan Hong | ff0a563 | 2017-08-21 18:39:29 -0700 | [diff] [blame] | 645 | |
Yifan Hong | a999357 | 2017-01-24 19:33:15 -0800 | [diff] [blame] | 646 | struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 647 | std::string elementName() const override { return "kernel"; } |
Yifan Hong | 86678e4 | 2018-07-26 11:38:54 -0700 | [diff] [blame] | 648 | void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d) const override { |
Yifan Hong | 250b55c | 2018-08-07 17:41:56 -0700 | [diff] [blame] | 649 | mutateNode(kernel, root, d, SerializeFlags::EVERYTHING); |
Yifan Hong | 86678e4 | 2018-07-26 11:38:54 -0700 | [diff] [blame] | 650 | } |
| 651 | void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d, |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 652 | SerializeFlags::Type flags) const override { |
Yifan Hong | 86678e4 | 2018-07-26 11:38:54 -0700 | [diff] [blame] | 653 | KernelVersion kv = kernel.mMinLts; |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 654 | if (!flags.isKernelMinorRevisionEnabled()) { |
Yifan Hong | 86678e4 | 2018-07-26 11:38:54 -0700 | [diff] [blame] | 655 | kv.minorRev = 0u; |
| 656 | } |
| 657 | appendAttr(root, "version", kv); |
| 658 | |
Yifan Hong | a39ecfe | 2019-12-11 17:55:30 -0800 | [diff] [blame] | 659 | if (kernel.getSourceMatrixLevel() != Level::UNSPECIFIED) { |
| 660 | appendAttr(root, "level", kernel.getSourceMatrixLevel()); |
| 661 | } |
| 662 | |
Yifan Hong | ff0a563 | 2017-08-21 18:39:29 -0700 | [diff] [blame] | 663 | if (!kernel.mConditions.empty()) { |
| 664 | appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d)); |
| 665 | } |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 666 | if (flags.isKernelConfigsEnabled()) { |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 667 | appendChildren(root, matrixKernelConfigConverter, kernel.mConfigs, d); |
Yifan Hong | 86678e4 | 2018-07-26 11:38:54 -0700 | [diff] [blame] | 668 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 669 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 670 | bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override { |
Yifan Hong | a39ecfe | 2019-12-11 17:55:30 -0800 | [diff] [blame] | 671 | Level sourceMatrixLevel = Level::UNSPECIFIED; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 672 | if (!parseAttr(root, "version", &object->mMinLts, error) || |
Yifan Hong | a39ecfe | 2019-12-11 17:55:30 -0800 | [diff] [blame] | 673 | !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &sourceMatrixLevel, error) || |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 674 | !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions, |
| 675 | error) || |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 676 | !parseChildren(root, matrixKernelConfigConverter, &object->mConfigs, error)) { |
Yifan Hong | 3f5489a | 2017-02-08 11:14:21 -0800 | [diff] [blame] | 677 | return false; |
| 678 | } |
Yifan Hong | a39ecfe | 2019-12-11 17:55:30 -0800 | [diff] [blame] | 679 | object->setSourceMatrixLevel(sourceMatrixLevel); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 680 | return true; |
| 681 | } |
| 682 | }; |
| 683 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 684 | MatrixKernelConverter matrixKernelConverter{}; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 685 | |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 686 | XmlTextConverter<FqInstance> fqInstanceConverter{"fqname"}; |
| 687 | |
Yifan Hong | a999357 | 2017-01-24 19:33:15 -0800 | [diff] [blame] | 688 | struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 689 | std::string elementName() const override { return "hal"; } |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 690 | void mutateNode(const ManifestHal& m, NodeType* root, DocType* d) const override { |
Yifan Hong | 250b55c | 2018-08-07 17:41:56 -0700 | [diff] [blame] | 691 | mutateNode(m, root, d, SerializeFlags::EVERYTHING); |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 692 | } |
| 693 | void mutateNode(const ManifestHal& hal, NodeType* root, DocType* d, |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 694 | SerializeFlags::Type flags) const override { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 695 | appendAttr(root, "format", hal.format); |
| 696 | appendTextElement(root, "name", hal.name, d); |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 697 | if (!hal.transportArch.empty()) { |
| 698 | appendChild(root, transportArchConverter(hal.transportArch, d)); |
| 699 | } |
| 700 | // Don't output <version> for format="aidl" |
| 701 | if (hal.format != HalFormat::AIDL) { |
| 702 | appendChildren(root, versionConverter, hal.versions, d); |
| 703 | } |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 704 | appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d); |
Yifan Hong | ce4289b | 2018-03-13 12:01:24 -0700 | [diff] [blame] | 705 | if (hal.isOverride()) { |
| 706 | appendAttr(root, "override", hal.isOverride()); |
Yifan Hong | 68d2306 | 2018-01-17 16:09:46 -0800 | [diff] [blame] | 707 | } |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 708 | |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 709 | if (flags.isFqnameEnabled()) { |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 710 | std::set<std::string> simpleFqInstances; |
| 711 | hal.forEachInstance([&simpleFqInstances](const auto& manifestInstance) { |
| 712 | simpleFqInstances.emplace(manifestInstance.getSimpleFqInstance()); |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 713 | return true; |
| 714 | }); |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 715 | appendTextElements(root, fqInstanceConverter.elementName(), simpleFqInstances, d); |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 716 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 717 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 718 | bool buildObject(ManifestHal* object, NodeType* root, std::string* error) const override { |
Yifan Hong | 476b63f | 2017-05-17 18:15:01 -0700 | [diff] [blame] | 719 | std::vector<HalInterface> interfaces; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 720 | if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) || |
Yifan Hong | ce4289b | 2018-03-13 12:01:24 -0700 | [diff] [blame] | 721 | !parseOptionalAttr(root, "override", false, &object->mIsOverride, error) || |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 722 | !parseTextElement(root, "name", &object->name, error) || |
| 723 | !parseOptionalChild(root, transportArchConverter, {}, &object->transportArch, error) || |
| 724 | !parseChildren(root, versionConverter, &object->versions, error) || |
| 725 | !parseChildren(root, halInterfaceConverter, &interfaces, error)) { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 726 | return false; |
| 727 | } |
Yifan Hong | e0bb98d | 2017-08-07 14:40:19 -0700 | [diff] [blame] | 728 | |
| 729 | switch (object->format) { |
| 730 | case HalFormat::HIDL: { |
| 731 | if (object->transportArch.empty()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 732 | *error = "HIDL HAL '" + object->name + "' should have <transport> defined."; |
Yifan Hong | e0bb98d | 2017-08-07 14:40:19 -0700 | [diff] [blame] | 733 | return false; |
| 734 | } |
| 735 | } break; |
| 736 | case HalFormat::NATIVE: { |
| 737 | if (!object->transportArch.empty()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 738 | *error = |
Yifan Hong | e0bb98d | 2017-08-07 14:40:19 -0700 | [diff] [blame] | 739 | "Native HAL '" + object->name + "' should not have <transport> defined."; |
| 740 | return false; |
| 741 | } |
| 742 | } break; |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 743 | case HalFormat::AIDL: { |
| 744 | if (!object->transportArch.empty()) { |
| 745 | LOG(WARNING) << "Ignoring <transport> on manifest <hal format=\"aidl\"> " |
| 746 | << object->name; |
| 747 | object->transportArch = {}; |
| 748 | } |
| 749 | if (!object->versions.empty()) { |
| 750 | LOG(WARNING) << "Ignoring <version> on manifest <hal format=\"aidl\"> " |
| 751 | << object->name; |
| 752 | object->versions.clear(); |
| 753 | } |
| 754 | // Insert fake version for AIDL HALs so that forEachInstance works. |
| 755 | object->versions.push_back(details::kFakeAidlVersion); |
| 756 | } break; |
Yifan Hong | e0bb98d | 2017-08-07 14:40:19 -0700 | [diff] [blame] | 757 | default: { |
| 758 | LOG(FATAL) << "Unhandled HalFormat " |
| 759 | << static_cast<typename std::underlying_type<HalFormat>::type>( |
| 760 | object->format); |
| 761 | } break; |
| 762 | } |
| 763 | if (!object->transportArch.isValid()) return false; |
| 764 | |
Yifan Hong | ec3b9b7 | 2017-02-23 13:24:42 -0800 | [diff] [blame] | 765 | object->interfaces.clear(); |
| 766 | for (auto &&interface : interfaces) { |
Yifan Hong | 7e9e04d | 2018-03-20 13:06:00 -0700 | [diff] [blame] | 767 | auto res = object->interfaces.emplace(interface.name(), std::move(interface)); |
Yifan Hong | ec3b9b7 | 2017-02-23 13:24:42 -0800 | [diff] [blame] | 768 | if (!res.second) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 769 | *error = "Duplicated interface entry \"" + res.first->first + |
| 770 | "\"; if additional instances are needed, add them to the " |
| 771 | "existing <interface> node."; |
Yifan Hong | ec3b9b7 | 2017-02-23 13:24:42 -0800 | [diff] [blame] | 772 | return false; |
| 773 | } |
| 774 | } |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 775 | if (!object->isValid()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 776 | *error = "'" + object->name + "' is not a valid Manifest HAL."; |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 777 | return false; |
| 778 | } |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 779 | // Do not check for target-side libvintf to avoid restricting upgrade accidentally. |
Yifan Hong | 6bce1a6 | 2018-01-31 13:30:04 -0800 | [diff] [blame] | 780 | #ifndef LIBVINTF_TARGET |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 781 | if (!checkAdditionalRestrictionsOnHal(*object, error)) { |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 782 | return false; |
| 783 | } |
| 784 | #endif |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 785 | |
| 786 | std::set<FqInstance> fqInstances; |
| 787 | if (!parseChildren(root, fqInstanceConverter, &fqInstances, error)) { |
| 788 | return false; |
| 789 | } |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 790 | std::set<FqInstance> fqInstancesToInsert; |
| 791 | for (auto& e : fqInstances) { |
Yifan Hong | 5541069 | 2018-05-01 19:08:51 -0700 | [diff] [blame] | 792 | if (e.hasPackage()) { |
| 793 | *error = "Should not specify package: \"" + e.string() + "\""; |
| 794 | return false; |
| 795 | } |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 796 | if (object->format == HalFormat::AIDL) { |
| 797 | // <fqname> in AIDL HALs should not contain version. Put in the fake |
| 798 | // kFakeAidlVersion so that compatibility check works. |
| 799 | FqInstance withFakeVersion; |
| 800 | if (!withFakeVersion.setTo(details::kFakeAidlVersion.majorVer, |
| 801 | details::kFakeAidlVersion.minorVer, e.getInterface(), |
| 802 | e.getInstance())) { |
| 803 | return false; |
| 804 | } |
| 805 | fqInstancesToInsert.emplace(std::move(withFakeVersion)); |
| 806 | } else { |
| 807 | fqInstancesToInsert.emplace(std::move(e)); |
| 808 | } |
Yifan Hong | 5541069 | 2018-05-01 19:08:51 -0700 | [diff] [blame] | 809 | } |
Yifan Hong | 934de62 | 2019-08-30 15:28:59 -0700 | [diff] [blame] | 810 | if (!object->insertInstances(fqInstancesToInsert, error)) { |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 811 | return false; |
| 812 | } |
| 813 | |
Yifan Hong | c54d32c | 2017-03-07 19:12:26 -0800 | [diff] [blame] | 814 | return true; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 815 | } |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 816 | |
Yifan Hong | 6bce1a6 | 2018-01-31 13:30:04 -0800 | [diff] [blame] | 817 | #ifndef LIBVINTF_TARGET |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 818 | private: |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 819 | bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal, std::string* error) const { |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 820 | if (hal.getName() == "netutils-wrapper") { |
| 821 | for (const Version& v : hal.versions) { |
| 822 | if (v.minorVer != 0) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 823 | *error = |
Yifan Hong | d9e4643 | 2017-08-15 17:14:52 -0700 | [diff] [blame] | 824 | "netutils-wrapper HAL must specify exactly one version x.0, " |
| 825 | "but minor version is not 0. Perhaps you mean '" + |
| 826 | to_string(Version{v.majorVer, 0}) + "'?"; |
| 827 | return false; |
| 828 | } |
| 829 | } |
| 830 | } |
| 831 | return true; |
| 832 | } |
| 833 | #endif |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 834 | }; |
| 835 | |
Yifan Hong | 4a5eb7b | 2017-02-16 18:19:26 -0800 | [diff] [blame] | 836 | // Convert ManifestHal from and to XML. Returned object is guaranteed to have |
| 837 | // .isValid() == true. |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 838 | ManifestHalConverter manifestHalConverter{}; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 839 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 840 | XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"}; |
| 841 | XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"}; |
Yifan Hong | 558380a | 2017-02-09 15:37:32 -0800 | [diff] [blame] | 842 | |
Yifan Hong | a999357 | 2017-01-24 19:33:15 -0800 | [diff] [blame] | 843 | struct SepolicyConverter : public XmlNodeConverter<Sepolicy> { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 844 | std::string elementName() const override { return "sepolicy"; } |
Yifan Hong | 558380a | 2017-02-09 15:37:32 -0800 | [diff] [blame] | 845 | void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override { |
| 846 | appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d)); |
Yifan Hong | 9a36158 | 2017-04-12 18:56:37 -0700 | [diff] [blame] | 847 | appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d); |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 848 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 849 | bool buildObject(Sepolicy* object, NodeType* root, std::string* error) const override { |
| 850 | if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion, |
| 851 | error) || |
| 852 | !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges, |
| 853 | error)) { |
Yifan Hong | 558380a | 2017-02-09 15:37:32 -0800 | [diff] [blame] | 854 | return false; |
| 855 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 856 | return true; |
| 857 | } |
| 858 | }; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 859 | SepolicyConverter sepolicyConverter{}; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 860 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 861 | [[deprecated]] XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"}; |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 862 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 863 | XmlTextConverter<std::string> vndkVersionConverter{"version"}; |
| 864 | XmlTextConverter<std::string> vndkLibraryConverter{"library"}; |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 865 | |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 866 | struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> { |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 867 | std::string elementName() const override { return "vndk"; } |
| 868 | void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override { |
| 869 | appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d)); |
| 870 | appendChildren(root, vndkLibraryConverter, object.mLibraries, d); |
| 871 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 872 | bool buildObject(Vndk* object, NodeType* root, std::string* error) const override { |
| 873 | if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange, error) || |
| 874 | !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) { |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 875 | return false; |
| 876 | } |
| 877 | return true; |
| 878 | } |
| 879 | }; |
| 880 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 881 | [[deprecated]] VndkConverter vndkConverter{}; |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 882 | |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 883 | struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> { |
| 884 | std::string elementName() const override { return "vendor-ndk"; } |
| 885 | void mutateNode(const VendorNdk& object, NodeType* root, DocType* d) const override { |
| 886 | appendChild(root, vndkVersionConverter(object.mVersion, d)); |
| 887 | appendChildren(root, vndkLibraryConverter, object.mLibraries, d); |
| 888 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 889 | bool buildObject(VendorNdk* object, NodeType* root, std::string* error) const override { |
| 890 | if (!parseChild(root, vndkVersionConverter, &object->mVersion, error) || |
| 891 | !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) { |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 892 | return false; |
| 893 | } |
| 894 | return true; |
| 895 | } |
| 896 | }; |
| 897 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 898 | VendorNdkConverter vendorNdkConverter{}; |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 899 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 900 | XmlTextConverter<std::string> systemSdkVersionConverter{"version"}; |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 901 | |
| 902 | struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> { |
| 903 | std::string elementName() const override { return "system-sdk"; } |
| 904 | void mutateNode(const SystemSdk& object, NodeType* root, DocType* d) const override { |
| 905 | appendChildren(root, systemSdkVersionConverter, object.versions(), d); |
| 906 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 907 | bool buildObject(SystemSdk* object, NodeType* root, std::string* error) const override { |
| 908 | return parseChildren(root, systemSdkVersionConverter, &object->mVersions, error); |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 909 | } |
| 910 | }; |
| 911 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 912 | SystemSdkConverter systemSdkConverter{}; |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 913 | |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 914 | struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> { |
| 915 | std::string elementName() const override { return "sepolicy"; } |
| 916 | void mutateNode(const Version &m, NodeType *root, DocType *d) const override { |
| 917 | appendChild(root, versionConverter(m, d)); |
| 918 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 919 | bool buildObject(Version* object, NodeType* root, std::string* error) const override { |
| 920 | return parseChild(root, versionConverter, object, error); |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 921 | } |
| 922 | }; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 923 | HalManifestSepolicyConverter halManifestSepolicyConverter{}; |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 924 | |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 925 | struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> { |
| 926 | std::string elementName() const override { return "xmlfile"; } |
| 927 | void mutateNode(const ManifestXmlFile& f, NodeType* root, DocType* d) const override { |
| 928 | appendTextElement(root, "name", f.name(), d); |
| 929 | appendChild(root, versionConverter(f.version(), d)); |
| 930 | if (!f.overriddenPath().empty()) { |
| 931 | appendTextElement(root, "path", f.overriddenPath(), d); |
| 932 | } |
| 933 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 934 | bool buildObject(ManifestXmlFile* object, NodeType* root, std::string* error) const override { |
| 935 | if (!parseTextElement(root, "name", &object->mName, error) || |
| 936 | !parseChild(root, versionConverter, &object->mVersion, error) || |
| 937 | !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) { |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 938 | return false; |
| 939 | } |
| 940 | return true; |
| 941 | } |
| 942 | }; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 943 | ManifestXmlFileConverter manifestXmlFileConverter{}; |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 944 | |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 945 | XmlPairConverter<std::pair<std::string, std::string>> kernelConfigConverter{ |
| 946 | "config", std::make_unique<XmlTextConverter<std::string>>("key"), |
| 947 | std::make_unique<XmlTextConverter<std::string>>("value")}; |
| 948 | |
| 949 | struct KernelInfoConverter : public XmlNodeConverter<KernelInfo> { |
| 950 | std::string elementName() const override { return "kernel"; } |
| 951 | void mutateNode(const KernelInfo& o, NodeType* root, DocType* d) const override { |
| 952 | mutateNode(o, root, d, SerializeFlags::EVERYTHING); |
| 953 | } |
| 954 | void mutateNode(const KernelInfo& o, NodeType* root, DocType* d, |
| 955 | SerializeFlags::Type flags) const override { |
| 956 | if (o.version() != KernelVersion{}) { |
| 957 | appendAttr(root, "version", o.version()); |
| 958 | } |
Yifan Hong | e624844 | 2019-12-11 13:33:00 -0800 | [diff] [blame] | 959 | if (o.level() != Level::UNSPECIFIED) { |
| 960 | appendAttr(root, "target-level", o.level()); |
| 961 | } |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 962 | if (flags.isKernelConfigsEnabled()) { |
| 963 | appendChildren(root, kernelConfigConverter, o.configs(), d); |
| 964 | } |
| 965 | } |
| 966 | bool buildObject(KernelInfo* o, NodeType* root, std::string* error) const override { |
| 967 | return parseOptionalAttr(root, "version", {}, &o->mVersion, error) && |
Yifan Hong | e624844 | 2019-12-11 13:33:00 -0800 | [diff] [blame] | 968 | parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &o->mLevel, error) && |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 969 | parseChildren(root, kernelConfigConverter, &o->mConfigs, error); |
| 970 | } |
| 971 | }; |
| 972 | |
| 973 | KernelInfoConverter kernelInfoConverter{}; |
| 974 | |
Yifan Hong | d2b7e64 | 2017-02-17 10:15:32 -0800 | [diff] [blame] | 975 | struct HalManifestConverter : public XmlNodeConverter<HalManifest> { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 976 | std::string elementName() const override { return "manifest"; } |
Yifan Hong | d2b7e64 | 2017-02-17 10:15:32 -0800 | [diff] [blame] | 977 | void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override { |
Yifan Hong | 250b55c | 2018-08-07 17:41:56 -0700 | [diff] [blame] | 978 | mutateNode(m, root, d, SerializeFlags::EVERYTHING); |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 979 | } |
| 980 | void mutateNode(const HalManifest& m, NodeType* root, DocType* d, |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 981 | SerializeFlags::Type flags) const override { |
Yifan Hong | 304cdab | 2018-08-02 16:03:59 -0700 | [diff] [blame] | 982 | if (flags.isMetaVersionEnabled()) { |
| 983 | appendAttr(root, "version", m.getMetaVersion()); |
| 984 | } |
| 985 | if (flags.isSchemaTypeEnabled()) { |
| 986 | appendAttr(root, "type", m.mType); |
| 987 | } |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 988 | |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 989 | if (flags.isHalsEnabled()) { |
Yifan Hong | 2b1efaa | 2018-03-13 12:36:38 -0700 | [diff] [blame] | 990 | appendChildren(root, manifestHalConverter, m.getHals(), d, flags); |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 991 | } |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 992 | if (m.mType == SchemaType::DEVICE) { |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 993 | if (flags.isSepolicyEnabled()) { |
Yifan Hong | 304cdab | 2018-08-02 16:03:59 -0700 | [diff] [blame] | 994 | if (m.device.mSepolicyVersion != Version{}) { |
| 995 | appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d)); |
| 996 | } |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 997 | } |
Yifan Hong | c393c71 | 2018-02-12 13:33:17 -0800 | [diff] [blame] | 998 | if (m.mLevel != Level::UNSPECIFIED) { |
| 999 | this->appendAttr(root, "target-level", m.mLevel); |
| 1000 | } |
Yifan Hong | a45f77d | 2018-12-03 16:42:52 -0800 | [diff] [blame] | 1001 | |
| 1002 | if (flags.isKernelEnabled()) { |
| 1003 | if (!!m.kernel()) { |
| 1004 | appendChild(root, kernelInfoConverter.serialize(*m.kernel(), d, flags)); |
| 1005 | } |
| 1006 | } |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 1007 | } else if (m.mType == SchemaType::FRAMEWORK) { |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1008 | if (flags.isVndkEnabled()) { |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1009 | #pragma clang diagnostic push |
| 1010 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1011 | appendChildren(root, vndkConverter, m.framework.mVndks, d); |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1012 | #pragma clang diagnostic pop |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 1013 | |
| 1014 | appendChildren(root, vendorNdkConverter, m.framework.mVendorNdks, d); |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1015 | } |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1016 | if (flags.isSsdkEnabled()) { |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 1017 | if (!m.framework.mSystemSdk.empty()) { |
| 1018 | appendChild(root, systemSdkConverter(m.framework.mSystemSdk, d)); |
| 1019 | } |
| 1020 | } |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 1021 | } |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1022 | |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1023 | if (flags.isXmlFilesEnabled()) { |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1024 | appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d); |
| 1025 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1026 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1027 | bool buildObject(HalManifest* object, NodeType* root, std::string* error) const override { |
Yifan Hong | a310411 | 2019-08-30 14:25:55 -0700 | [diff] [blame] | 1028 | Version metaVersion; |
| 1029 | if (!parseAttr(root, "version", &metaVersion, error)) return false; |
| 1030 | if (metaVersion > kMetaVersion) { |
| 1031 | *error = "Unrecognized manifest.version " + to_string(metaVersion) + " (libvintf@" + |
| 1032 | to_string(kMetaVersion) + ")"; |
Yifan Hong | 7c7d706 | 2017-04-04 16:26:51 -0700 | [diff] [blame] | 1033 | return false; |
| 1034 | } |
Yifan Hong | a310411 | 2019-08-30 14:25:55 -0700 | [diff] [blame] | 1035 | |
| 1036 | std::vector<ManifestHal> hals; |
| 1037 | if (!parseAttr(root, "type", &object->mType, error) || |
| 1038 | !parseChildren(root, manifestHalConverter, &hals, error)) { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1039 | return false; |
| 1040 | } |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 1041 | if (object->mType == SchemaType::DEVICE) { |
| 1042 | // tags for device hal manifest only. |
Yifan Hong | 383f945 | 2017-04-17 11:20:41 -0700 | [diff] [blame] | 1043 | // <sepolicy> can be missing because it can be determined at build time, not hard-coded |
| 1044 | // in the XML file. |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 1045 | if (!parseOptionalChild(root, halManifestSepolicyConverter, {}, |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1046 | &object->device.mSepolicyVersion, error)) { |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 1047 | return false; |
| 1048 | } |
Yifan Hong | c393c71 | 2018-02-12 13:33:17 -0800 | [diff] [blame] | 1049 | |
| 1050 | if (!parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel, |
| 1051 | error)) { |
| 1052 | return false; |
| 1053 | } |
Yifan Hong | a45f77d | 2018-12-03 16:42:52 -0800 | [diff] [blame] | 1054 | |
| 1055 | if (!parseOptionalChild(root, kernelInfoConverter, &object->device.mKernel, error)) { |
| 1056 | return false; |
| 1057 | } |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 1058 | } else if (object->mType == SchemaType::FRAMEWORK) { |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1059 | #pragma clang diagnostic push |
| 1060 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1061 | if (!parseChildren(root, vndkConverter, &object->framework.mVndks, error)) { |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 1062 | return false; |
| 1063 | } |
| 1064 | for (const auto &vndk : object->framework.mVndks) { |
| 1065 | if (!vndk.mVersionRange.isSingleVersion()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1066 | *error = "vndk.version " + to_string(vndk.mVersionRange) + |
| 1067 | " cannot be a range for manifests"; |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 1068 | return false; |
| 1069 | } |
| 1070 | } |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1071 | #pragma clang diagnostic pop |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 1072 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1073 | if (!parseChildren(root, vendorNdkConverter, &object->framework.mVendorNdks, error)) { |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 1074 | return false; |
| 1075 | } |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 1076 | |
Yifan Hong | 0bfbc12 | 2018-02-02 13:27:29 -0800 | [diff] [blame] | 1077 | std::set<std::string> vendorNdkVersions; |
| 1078 | for (const auto& vendorNdk : object->framework.mVendorNdks) { |
| 1079 | if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1080 | *error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version(); |
Yifan Hong | 0bfbc12 | 2018-02-02 13:27:29 -0800 | [diff] [blame] | 1081 | return false; |
| 1082 | } |
| 1083 | vendorNdkVersions.insert(vendorNdk.version()); |
| 1084 | } |
| 1085 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1086 | if (!parseOptionalChild(root, systemSdkConverter, {}, &object->framework.mSystemSdk, |
| 1087 | error)) { |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 1088 | return false; |
| 1089 | } |
Yifan Hong | 2a3dd08 | 2017-04-04 17:15:35 -0700 | [diff] [blame] | 1090 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1091 | for (auto &&hal : hals) { |
Yifan Hong | 79dcc1f | 2017-05-22 14:35:19 -0700 | [diff] [blame] | 1092 | std::string description{hal.name}; |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 1093 | if (!object->add(std::move(hal))) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1094 | *error = "Duplicated manifest.hal entry " + description; |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 1095 | return false; |
| 1096 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1097 | } |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1098 | |
| 1099 | std::vector<ManifestXmlFile> xmlFiles; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1100 | if (!parseChildren(root, manifestXmlFileConverter, &xmlFiles, error)) { |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1101 | return false; |
| 1102 | } |
| 1103 | for (auto&& xmlFile : xmlFiles) { |
| 1104 | std::string description{xmlFile.name()}; |
| 1105 | if (!object->addXmlFile(std::move(xmlFile))) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1106 | *error = "Duplicated manifest.xmlfile entry " + description + |
| 1107 | "; entries cannot have duplicated name and version"; |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1108 | return false; |
| 1109 | } |
| 1110 | } |
| 1111 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1112 | return true; |
| 1113 | } |
| 1114 | }; |
| 1115 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1116 | HalManifestConverter halManifestConverter{}; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1117 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1118 | XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"}; |
Yifan Hong | f302930 | 2017-04-12 17:23:49 -0700 | [diff] [blame] | 1119 | struct AvbConverter : public XmlNodeConverter<Version> { |
| 1120 | std::string elementName() const override { return "avb"; } |
| 1121 | void mutateNode(const Version &m, NodeType *root, DocType *d) const override { |
| 1122 | appendChild(root, avbVersionConverter(m, d)); |
| 1123 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1124 | bool buildObject(Version* object, NodeType* root, std::string* error) const override { |
| 1125 | return parseChild(root, avbVersionConverter, object, error); |
Yifan Hong | f302930 | 2017-04-12 17:23:49 -0700 | [diff] [blame] | 1126 | } |
| 1127 | }; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1128 | AvbConverter avbConverter{}; |
Yifan Hong | f302930 | 2017-04-12 17:23:49 -0700 | [diff] [blame] | 1129 | |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1130 | struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> { |
| 1131 | std::string elementName() const override { return "xmlfile"; } |
| 1132 | void mutateNode(const MatrixXmlFile& f, NodeType* root, DocType* d) const override { |
| 1133 | appendTextElement(root, "name", f.name(), d); |
| 1134 | appendAttr(root, "format", f.format()); |
| 1135 | appendAttr(root, "optional", f.optional()); |
| 1136 | appendChild(root, versionRangeConverter(f.versionRange(), d)); |
| 1137 | if (!f.overriddenPath().empty()) { |
| 1138 | appendTextElement(root, "path", f.overriddenPath(), d); |
| 1139 | } |
| 1140 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1141 | bool buildObject(MatrixXmlFile* object, NodeType* root, std::string* error) const override { |
| 1142 | if (!parseTextElement(root, "name", &object->mName, error) || |
| 1143 | !parseAttr(root, "format", &object->mFormat, error) || |
| 1144 | !parseOptionalAttr(root, "optional", false, &object->mOptional, error) || |
| 1145 | !parseChild(root, versionRangeConverter, &object->mVersionRange, error) || |
| 1146 | !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) { |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1147 | return false; |
| 1148 | } |
| 1149 | return true; |
| 1150 | } |
| 1151 | }; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1152 | MatrixXmlFileConverter matrixXmlFileConverter{}; |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1153 | |
Yifan Hong | a999357 | 2017-01-24 19:33:15 -0800 | [diff] [blame] | 1154 | struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> { |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1155 | std::string elementName() const override { return "compatibility-matrix"; } |
| 1156 | void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override { |
Yifan Hong | 250b55c | 2018-08-07 17:41:56 -0700 | [diff] [blame] | 1157 | mutateNode(m, root, d, SerializeFlags::EVERYTHING); |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1158 | } |
| 1159 | void mutateNode(const CompatibilityMatrix& m, NodeType* root, DocType* d, |
Yifan Hong | ba588bc | 2018-08-08 14:19:41 -0700 | [diff] [blame] | 1160 | SerializeFlags::Type flags) const override { |
Yifan Hong | 304cdab | 2018-08-02 16:03:59 -0700 | [diff] [blame] | 1161 | if (flags.isMetaVersionEnabled()) { |
Yifan Hong | a310411 | 2019-08-30 14:25:55 -0700 | [diff] [blame] | 1162 | appendAttr(root, "version", kMetaVersion); |
Yifan Hong | 304cdab | 2018-08-02 16:03:59 -0700 | [diff] [blame] | 1163 | } |
| 1164 | if (flags.isSchemaTypeEnabled()) { |
| 1165 | appendAttr(root, "type", m.mType); |
| 1166 | } |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1167 | |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1168 | if (flags.isHalsEnabled()) { |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1169 | appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d); |
| 1170 | } |
Yifan Hong | 7c7d706 | 2017-04-04 16:26:51 -0700 | [diff] [blame] | 1171 | if (m.mType == SchemaType::FRAMEWORK) { |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1172 | if (flags.isKernelEnabled()) { |
Yifan Hong | 86678e4 | 2018-07-26 11:38:54 -0700 | [diff] [blame] | 1173 | appendChildren(root, matrixKernelConverter, m.framework.mKernels, d, flags); |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1174 | } |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1175 | if (flags.isSepolicyEnabled()) { |
Yifan Hong | 244970c | 2018-01-23 15:29:27 -0800 | [diff] [blame] | 1176 | if (!(m.framework.mSepolicy == Sepolicy{})) { |
| 1177 | appendChild(root, sepolicyConverter(m.framework.mSepolicy, d)); |
| 1178 | } |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1179 | } |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1180 | if (flags.isAvbEnabled()) { |
Yifan Hong | 244970c | 2018-01-23 15:29:27 -0800 | [diff] [blame] | 1181 | if (!(m.framework.mAvbMetaVersion == Version{})) { |
| 1182 | appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d)); |
| 1183 | } |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1184 | } |
Yifan Hong | c393c71 | 2018-02-12 13:33:17 -0800 | [diff] [blame] | 1185 | if (m.mLevel != Level::UNSPECIFIED) { |
| 1186 | this->appendAttr(root, "level", m.mLevel); |
| 1187 | } |
Yifan Hong | 03d2d4a | 2017-04-12 17:34:14 -0700 | [diff] [blame] | 1188 | } else if (m.mType == SchemaType::DEVICE) { |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1189 | if (flags.isVndkEnabled()) { |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1190 | #pragma clang diagnostic push |
| 1191 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
Yifan Hong | 9e1f940 | 2018-01-09 16:14:24 -0800 | [diff] [blame] | 1192 | if (!(m.device.mVndk == Vndk{})) { |
| 1193 | appendChild(root, vndkConverter(m.device.mVndk, d)); |
| 1194 | } |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1195 | #pragma clang diagnostic pop |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 1196 | |
| 1197 | if (!(m.device.mVendorNdk == VendorNdk{})) { |
| 1198 | appendChild(root, vendorNdkConverter(m.device.mVendorNdk, d)); |
| 1199 | } |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1200 | } |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 1201 | |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1202 | if (flags.isSsdkEnabled()) { |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 1203 | if (!m.device.mSystemSdk.empty()) { |
| 1204 | appendChild(root, systemSdkConverter(m.device.mSystemSdk, d)); |
| 1205 | } |
| 1206 | } |
Yifan Hong | 7c7d706 | 2017-04-04 16:26:51 -0700 | [diff] [blame] | 1207 | } |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1208 | |
Yifan Hong | a1b112d | 2018-08-07 17:44:10 -0700 | [diff] [blame] | 1209 | if (flags.isXmlFilesEnabled()) { |
Yifan Hong | a2635c4 | 2017-12-12 13:20:33 -0800 | [diff] [blame] | 1210 | appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d); |
| 1211 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1212 | } |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1213 | bool buildObject(CompatibilityMatrix* object, NodeType* root, |
| 1214 | std::string* error) const override { |
Yifan Hong | a310411 | 2019-08-30 14:25:55 -0700 | [diff] [blame] | 1215 | Version metaVersion; |
| 1216 | if (!parseAttr(root, "version", &metaVersion, error)) return false; |
| 1217 | if (metaVersion > kMetaVersion) { |
| 1218 | *error = "Unrecognized compatibility-matrix.version " + to_string(metaVersion) + |
| 1219 | " (libvintf@" + to_string(kMetaVersion) + ")"; |
| 1220 | return false; |
| 1221 | } |
| 1222 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1223 | std::vector<MatrixHal> hals; |
Yifan Hong | a310411 | 2019-08-30 14:25:55 -0700 | [diff] [blame] | 1224 | if (!parseAttr(root, "type", &object->mType, error) || |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1225 | !parseChildren(root, matrixHalConverter, &hals, error)) { |
Yifan Hong | 7c7d706 | 2017-04-04 16:26:51 -0700 | [diff] [blame] | 1226 | return false; |
| 1227 | } |
| 1228 | |
| 1229 | if (object->mType == SchemaType::FRAMEWORK) { |
Yifan Hong | 1e5a054 | 2017-04-28 14:37:56 -0700 | [diff] [blame] | 1230 | // <avb> and <sepolicy> can be missing because it can be determined at build time, not |
| 1231 | // hard-coded in the XML file. |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1232 | if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels, error) || |
| 1233 | !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy, |
| 1234 | error) || |
| 1235 | !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion, |
| 1236 | error)) { |
Yifan Hong | 7c7d706 | 2017-04-04 16:26:51 -0700 | [diff] [blame] | 1237 | return false; |
| 1238 | } |
Yifan Hong | f4a2729 | 2017-08-23 15:14:02 -0700 | [diff] [blame] | 1239 | |
| 1240 | std::set<Version> seenKernelVersions; |
| 1241 | for (const auto& kernel : object->framework.mKernels) { |
| 1242 | Version minLts(kernel.minLts().version, kernel.minLts().majorRev); |
| 1243 | if (seenKernelVersions.find(minLts) != seenKernelVersions.end()) { |
| 1244 | continue; |
| 1245 | } |
| 1246 | if (!kernel.conditions().empty()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1247 | *error = "First <kernel> for version " + to_string(minLts) + |
| 1248 | " must have empty <conditions> for backwards compatibility."; |
Yifan Hong | f4a2729 | 2017-08-23 15:14:02 -0700 | [diff] [blame] | 1249 | return false; |
| 1250 | } |
| 1251 | seenKernelVersions.insert(minLts); |
| 1252 | } |
| 1253 | |
Yifan Hong | c393c71 | 2018-02-12 13:33:17 -0800 | [diff] [blame] | 1254 | if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel, error)) { |
| 1255 | return false; |
| 1256 | } |
| 1257 | |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 1258 | } else if (object->mType == SchemaType::DEVICE) { |
Yifan Hong | 0f85ac3 | 2017-04-28 14:22:16 -0700 | [diff] [blame] | 1259 | // <vndk> can be missing because it can be determined at build time, not hard-coded |
| 1260 | // in the XML file. |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1261 | #pragma clang diagnostic push |
| 1262 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1263 | if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk, error)) { |
Yifan Hong | a04e147 | 2017-04-05 13:15:34 -0700 | [diff] [blame] | 1264 | return false; |
| 1265 | } |
Yifan Hong | 0f529fa | 2018-01-10 14:51:59 -0800 | [diff] [blame] | 1266 | #pragma clang diagnostic pop |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 1267 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1268 | if (!parseOptionalChild(root, vendorNdkConverter, {}, &object->device.mVendorNdk, |
| 1269 | error)) { |
Yifan Hong | feb454e | 2018-01-09 16:16:40 -0800 | [diff] [blame] | 1270 | return false; |
| 1271 | } |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 1272 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1273 | if (!parseOptionalChild(root, systemSdkConverter, {}, &object->device.mSystemSdk, |
| 1274 | error)) { |
Yifan Hong | a28729e | 2018-01-17 13:40:35 -0800 | [diff] [blame] | 1275 | return false; |
| 1276 | } |
Yifan Hong | 7c7d706 | 2017-04-04 16:26:51 -0700 | [diff] [blame] | 1277 | } |
| 1278 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1279 | for (auto &&hal : hals) { |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 1280 | if (!object->add(std::move(hal))) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1281 | *error = "Duplicated compatibility-matrix.hal entry"; |
Yifan Hong | 33466ad | 2017-02-24 11:31:37 -0800 | [diff] [blame] | 1282 | return false; |
| 1283 | } |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1284 | } |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1285 | |
| 1286 | std::vector<MatrixXmlFile> xmlFiles; |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1287 | if (!parseChildren(root, matrixXmlFileConverter, &xmlFiles, error)) { |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1288 | return false; |
| 1289 | } |
| 1290 | for (auto&& xmlFile : xmlFiles) { |
| 1291 | if (!xmlFile.optional()) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1292 | *error = "compatibility-matrix.xmlfile entry " + xmlFile.name() + |
| 1293 | " has to be optional for compatibility matrix version 1.0"; |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1294 | return false; |
| 1295 | } |
| 1296 | std::string description{xmlFile.name()}; |
| 1297 | if (!object->addXmlFile(std::move(xmlFile))) { |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1298 | *error = "Duplicated compatibility-matrix.xmlfile entry " + description; |
Yifan Hong | d485790 | 2017-06-13 14:13:56 -0700 | [diff] [blame] | 1299 | return false; |
| 1300 | } |
| 1301 | } |
| 1302 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1303 | return true; |
| 1304 | } |
| 1305 | }; |
| 1306 | |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1307 | CompatibilityMatrixConverter compatibilityMatrixConverter{}; |
Yifan Hong | 4a5eb7b | 2017-02-16 18:19:26 -0800 | [diff] [blame] | 1308 | |
| 1309 | // Publicly available as in parse_xml.h |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1310 | XmlConverter<HalManifest>& gHalManifestConverter = halManifestConverter; |
| 1311 | XmlConverter<CompatibilityMatrix>& gCompatibilityMatrixConverter = compatibilityMatrixConverter; |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1312 | |
Yifan Hong | 4a5eb7b | 2017-02-16 18:19:26 -0800 | [diff] [blame] | 1313 | // For testing in LibVintfTest |
Yifan Hong | 9475706 | 2018-02-09 16:36:31 -0800 | [diff] [blame] | 1314 | XmlConverter<Version>& gVersionConverter = versionConverter; |
| 1315 | XmlConverter<KernelConfigTypedValue>& gKernelConfigTypedValueConverter = |
| 1316 | kernelConfigTypedValueConverter; |
| 1317 | XmlConverter<MatrixHal>& gMatrixHalConverter = matrixHalConverter; |
| 1318 | XmlConverter<ManifestHal>& gManifestHalConverter = manifestHalConverter; |
Yifan Hong | 180c510 | 2018-11-02 16:26:48 -0700 | [diff] [blame] | 1319 | XmlConverter<KernelInfo>& gKernelInfoConverter = kernelInfoConverter; |
Yifan Hong | 4a5eb7b | 2017-02-16 18:19:26 -0800 | [diff] [blame] | 1320 | |
Yifan Hong | 676447a | 2016-11-15 12:57:23 -0800 | [diff] [blame] | 1321 | } // namespace vintf |
| 1322 | } // namespace android |