• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // Convert objects from and to xml.
18 
19 #define LOG_TAG "libvintf"
20 #include <android-base/logging.h>
21 
22 #include "parse_xml.h"
23 
24 #include <type_traits>
25 
26 #include <tinyxml2.h>
27 
28 #include "Regex.h"
29 #include "constants.h"
30 #include "parse_string.h"
31 
32 namespace android {
33 namespace vintf {
34 
35 // --------------- tinyxml2 details
36 
37 using NodeType = tinyxml2::XMLElement;
38 using DocType = tinyxml2::XMLDocument;
39 
40 // caller is responsible for deleteDocument() call
createDocument()41 inline DocType *createDocument() {
42     return new tinyxml2::XMLDocument();
43 }
44 
45 // caller is responsible for deleteDocument() call
createDocument(const std::string & xml)46 inline DocType *createDocument(const std::string &xml) {
47     DocType *doc = new tinyxml2::XMLDocument();
48     if (doc->Parse(xml.c_str()) == tinyxml2::XML_SUCCESS) {
49         return doc;
50     }
51     delete doc;
52     return nullptr;
53 }
54 
deleteDocument(DocType * d)55 inline void deleteDocument(DocType *d) {
56     delete d;
57 }
58 
printDocument(DocType * d)59 inline std::string printDocument(DocType *d) {
60     tinyxml2::XMLPrinter p;
61     d->Print(&p);
62     return std::string{p.CStr()};
63 }
64 
createNode(const std::string & name,DocType * d)65 inline NodeType *createNode(const std::string &name, DocType *d) {
66     return d->NewElement(name.c_str());
67 }
68 
appendChild(NodeType * parent,NodeType * child)69 inline void appendChild(NodeType *parent, NodeType *child) {
70     parent->InsertEndChild(child);
71 }
72 
appendChild(DocType * parent,NodeType * child)73 inline void appendChild(DocType *parent, NodeType *child) {
74     parent->InsertEndChild(child);
75 }
76 
appendStrAttr(NodeType * e,const std::string & attrName,const std::string & attr)77 inline void appendStrAttr(NodeType *e, const std::string &attrName, const std::string &attr) {
78     e->SetAttribute(attrName.c_str(), attr.c_str());
79 }
80 
81 // text -> text
appendText(NodeType * parent,const std::string & text,DocType * d)82 inline void appendText(NodeType *parent, const std::string &text, DocType *d) {
83     parent->InsertEndChild(d->NewText(text.c_str()));
84 }
85 
nameOf(NodeType * root)86 inline std::string nameOf(NodeType *root) {
87     return root->Name() == NULL ? "" : root->Name();
88 }
89 
getText(NodeType * root)90 inline std::string getText(NodeType *root) {
91     return root->GetText() == NULL ? "" : root->GetText();
92 }
93 
getChild(NodeType * parent,const std::string & name)94 inline NodeType *getChild(NodeType *parent, const std::string &name) {
95     return parent->FirstChildElement(name.c_str());
96 }
97 
getRootChild(DocType * parent)98 inline NodeType *getRootChild(DocType *parent) {
99     return parent->FirstChildElement();
100 }
101 
getChildren(NodeType * parent,const std::string & name)102 inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) {
103     std::vector<NodeType *> v;
104     for (NodeType *child = parent->FirstChildElement(name.c_str());
105          child != nullptr;
106          child = child->NextSiblingElement(name.c_str())) {
107         v.push_back(child);
108     }
109     return v;
110 }
111 
getAttr(NodeType * root,const std::string & attrName,std::string * s)112 inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) {
113     const char *c = root->Attribute(attrName.c_str());
114     if (c == NULL)
115         return false;
116     *s = c;
117     return true;
118 }
119 
120 // --------------- tinyxml2 details end.
121 
122 // Helper functions for XmlConverter
parse(const std::string & attrText,bool * attr)123 static bool parse(const std::string &attrText, bool *attr) {
124     if (attrText == "true" || attrText == "1") {
125         *attr = true;
126         return true;
127     }
128     if (attrText == "false" || attrText == "0") {
129         *attr = false;
130         return true;
131     }
132     return false;
133 }
134 
135 // ---------------------- XmlNodeConverter definitions
136 
137 template<typename Object>
138 struct XmlNodeConverter : public XmlConverter<Object> {
XmlNodeConverterandroid::vintf::XmlNodeConverter139     XmlNodeConverter() {}
~XmlNodeConverterandroid::vintf::XmlNodeConverter140     virtual ~XmlNodeConverter() {}
141 
142     // sub-types should implement these.
143     virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0;
mutateNodeandroid::vintf::XmlNodeConverter144     virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags) const {
145         mutateNode(o, n, d);
146     }
147     virtual bool buildObject(Object* o, NodeType* n, std::string* error) const = 0;
148     virtual std::string elementName() const = 0;
149 
150     // convenience methods for user
lastErrorandroid::vintf::XmlNodeConverter151     inline const std::string& lastError() const override { return mLastError; }
serializeandroid::vintf::XmlNodeConverter152     inline NodeType* serialize(const Object& o, DocType* d,
153                                SerializeFlags flags = EVERYTHING) const {
154         NodeType *root = createNode(this->elementName(), d);
155         this->mutateNode(o, root, d, flags);
156         return root;
157     }
serializeandroid::vintf::XmlNodeConverter158     inline std::string serialize(const Object& o, SerializeFlags flags) const override {
159         DocType *doc = createDocument();
160         appendChild(doc, serialize(o, doc, flags));
161         std::string s = printDocument(doc);
162         deleteDocument(doc);
163         return s;
164     }
deserializeandroid::vintf::XmlNodeConverter165     inline bool deserialize(Object* object, NodeType* root) {
166         bool ret = deserialize(object, root, &mLastError);
167         return ret;
168     }
deserializeandroid::vintf::XmlNodeConverter169     inline bool deserialize(Object* o, const std::string& xml) override {
170         bool ret = (*this)(o, xml, &mLastError);
171         return ret;
172     }
deserializeandroid::vintf::XmlNodeConverter173     inline bool deserialize(Object* object, NodeType* root, std::string* error) const {
174         if (nameOf(root) != this->elementName()) {
175             return false;
176         }
177         return this->buildObject(object, root, error);
178     }
operator ()android::vintf::XmlNodeConverter179     inline bool operator()(Object* o, const std::string& xml, std::string* error) const override {
180         std::string errorBuffer;
181         if (error == nullptr) error = &errorBuffer;
182 
183         auto doc = createDocument(xml);
184         if (doc == nullptr) {
185             *error = "Not a valid XML";
186             return false;
187         }
188         bool ret = deserialize(o, getRootChild(doc), error);
189         deleteDocument(doc);
190         return ret;
191     }
operator ()android::vintf::XmlNodeConverter192     inline NodeType *operator()(const Object &o, DocType *d) const {
193         return serialize(o, d);
194     }
operator ()android::vintf::XmlNodeConverter195     inline std::string operator()(const Object& o, SerializeFlags flags) const override {
196         return serialize(o, flags);
197     }
operator ()android::vintf::XmlNodeConverter198     inline bool operator()(Object* o, NodeType* node) { return deserialize(o, node); }
operator ()android::vintf::XmlNodeConverter199     inline bool operator()(Object* o, const std::string& xml) override {
200         return deserialize(o, xml);
201     }
202 
203     // convenience methods for implementor.
204 
205     // All append* functions helps mutateNode() to serialize the object into XML.
206     template <typename T>
appendAttrandroid::vintf::XmlNodeConverter207     inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const {
208         return appendStrAttr(e, attrName, ::android::vintf::to_string(attr));
209     }
210 
appendAttrandroid::vintf::XmlNodeConverter211     inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const {
212         return appendStrAttr(e, attrName, attr ? "true" : "false");
213     }
214 
215     // text -> <name>text</name>
appendTextElementandroid::vintf::XmlNodeConverter216     inline void appendTextElement(NodeType *parent, const std::string &name,
217                 const std::string &text, DocType *d) const {
218         NodeType *c = createNode(name, d);
219         appendText(c, text, d);
220         appendChild(parent, c);
221     }
222 
223     // text -> <name>text</name>
224     template<typename Array>
appendTextElementsandroid::vintf::XmlNodeConverter225     inline void appendTextElements(NodeType *parent, const std::string &name,
226                 const Array &array, DocType *d) const {
227         for (const std::string &text : array) {
228             NodeType *c = createNode(name, d);
229             appendText(c, text, d);
230             appendChild(parent, c);
231         }
232     }
233 
234     template <typename T, typename Array>
appendChildrenandroid::vintf::XmlNodeConverter235     inline void appendChildren(NodeType* parent, const XmlNodeConverter<T>& conv,
236                                const Array& array, DocType* d,
237                                SerializeFlags flags = SerializeFlag::EVERYTHING) const {
238         for (const T &t : array) {
239             appendChild(parent, conv.serialize(t, d, flags));
240         }
241     }
242 
243     // All parse* functions helps buildObject() to deserialize XML to the object. Returns
244     // true if deserialization is successful, false if any error, and "error" will be
245     // set to error message.
246     template <typename T>
parseOptionalAttrandroid::vintf::XmlNodeConverter247     inline bool parseOptionalAttr(NodeType* root, const std::string& attrName, T&& defaultValue,
248                                   T* attr, std::string* /* error */) const {
249         std::string attrText;
250         bool success = getAttr(root, attrName, &attrText) &&
251                        ::android::vintf::parse(attrText, attr);
252         if (!success) {
253             *attr = std::move(defaultValue);
254         }
255         return true;
256     }
257 
258     template <typename T>
parseAttrandroid::vintf::XmlNodeConverter259     inline bool parseAttr(NodeType* root, const std::string& attrName, T* attr,
260                           std::string* error) const {
261         std::string attrText;
262         bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
263         if (!ret) {
264             *error = "Could not find/parse attr with name \"" + attrName + "\" and value \"" +
265                      attrText + "\" for element <" + elementName() + ">";
266         }
267         return ret;
268     }
269 
parseAttrandroid::vintf::XmlNodeConverter270     inline bool parseAttr(NodeType* root, const std::string& attrName, std::string* attr,
271                           std::string* error) const {
272         bool ret = getAttr(root, attrName, attr);
273         if (!ret) {
274             *error = "Could not find attr with name \"" + attrName + "\" for element <" +
275                      elementName() + ">";
276         }
277         return ret;
278     }
279 
parseTextElementandroid::vintf::XmlNodeConverter280     inline bool parseTextElement(NodeType* root, const std::string& elementName, std::string* s,
281                                  std::string* error) const {
282         NodeType *child = getChild(root, elementName);
283         if (child == nullptr) {
284             *error = "Could not find element with name <" + elementName + "> in element <" +
285                      this->elementName() + ">";
286             return false;
287         }
288         *s = getText(child);
289         return true;
290     }
291 
parseOptionalTextElementandroid::vintf::XmlNodeConverter292     inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName,
293                                          std::string&& defaultValue, std::string* s,
294                                          std::string* /* error */) const {
295         NodeType* child = getChild(root, elementName);
296         *s = child == nullptr ? std::move(defaultValue) : getText(child);
297         return true;
298     }
299 
parseTextElementsandroid::vintf::XmlNodeConverter300     inline bool parseTextElements(NodeType* root, const std::string& elementName,
301                                   std::vector<std::string>* v, std::string* /* error */) const {
302         auto nodes = getChildren(root, elementName);
303         v->resize(nodes.size());
304         for (size_t i = 0; i < nodes.size(); ++i) {
305             v->at(i) = getText(nodes[i]);
306         }
307         return true;
308     }
309 
310     template <typename T>
parseChildandroid::vintf::XmlNodeConverter311     inline bool parseChild(NodeType* root, const XmlNodeConverter<T>& conv, T* t,
312                            std::string* error) const {
313         NodeType *child = getChild(root, conv.elementName());
314         if (child == nullptr) {
315             *error = "Could not find element with name <" + conv.elementName() + "> in element <" +
316                      this->elementName() + ">";
317             return false;
318         }
319         return conv.deserialize(t, child, error);
320     }
321 
322     template <typename T>
parseOptionalChildandroid::vintf::XmlNodeConverter323     inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
324                                    T&& defaultValue, T* t, std::string* error) const {
325         NodeType *child = getChild(root, conv.elementName());
326         if (child == nullptr) {
327             *t = std::move(defaultValue);
328             return true;
329         }
330         return conv.deserialize(t, child, error);
331     }
332 
333     template <typename T>
parseChildrenandroid::vintf::XmlNodeConverter334     inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v,
335                               std::string* error) const {
336         auto nodes = getChildren(root, conv.elementName());
337         v->resize(nodes.size());
338         for (size_t i = 0; i < nodes.size(); ++i) {
339             if (!conv.deserialize(&v->at(i), nodes[i], error)) {
340                 *error = "Could not parse element with name <" + conv.elementName() +
341                          "> in element <" + this->elementName() + ">: " + *error;
342                 return false;
343             }
344         }
345         return true;
346     }
347 
348     template <typename T>
parseChildrenandroid::vintf::XmlNodeConverter349     inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::set<T>* s,
350                               std::string* error) const {
351         std::vector<T> vec;
352         if (!parseChildren(root, conv, &vec, error)) {
353             return false;
354         }
355         s->clear();
356         s->insert(vec.begin(), vec.end());
357         if (s->size() != vec.size()) {
358             *error = "Duplicated elements <" + conv.elementName() + "> in element <" +
359                      this->elementName() + ">";
360             s->clear();
361             return false;
362         }
363         return true;
364     }
365 
parseTextandroid::vintf::XmlNodeConverter366     inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const {
367         *s = getText(node);
368         return true;
369     }
370 
371     template <typename T>
parseTextandroid::vintf::XmlNodeConverter372     inline bool parseText(NodeType* node, T* s, std::string* error) const {
373         std::string text = getText(node);
374         bool ret = ::android::vintf::parse(text, s);
375         if (!ret) {
376             *error = "Could not parse text \"" + text + "\" in element <" + elementName() + ">";
377         }
378         return ret;
379     }
380 
381    private:
382     mutable std::string mLastError;
383 };
384 
385 template<typename Object>
386 struct XmlTextConverter : public XmlNodeConverter<Object> {
XmlTextConverterandroid::vintf::XmlTextConverter387     XmlTextConverter(const std::string &elementName)
388         : mElementName(elementName) {}
389 
mutateNodeandroid::vintf::XmlTextConverter390     virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override {
391         appendText(root, ::android::vintf::to_string(object), d);
392     }
buildObjectandroid::vintf::XmlTextConverter393     virtual bool buildObject(Object* object, NodeType* root, std::string* error) const override {
394         return this->parseText(root, object, error);
395     }
elementNameandroid::vintf::XmlTextConverter396     virtual std::string elementName() const { return mElementName; };
397 private:
398     std::string mElementName;
399 };
400 
401 // ---------------------- XmlNodeConverter definitions end
402 
403 XmlTextConverter<Version> versionConverter{"version"};
404 
405 XmlTextConverter<VersionRange> versionRangeConverter{"version"};
406 
407 XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
408 
409 struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
elementNameandroid::vintf::TransportArchConverter410     std::string elementName() const override { return "transport"; }
mutateNodeandroid::vintf::TransportArchConverter411     void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override {
412         if (object.arch != Arch::ARCH_EMPTY) {
413             appendAttr(root, "arch", object.arch);
414         }
415         appendText(root, ::android::vintf::to_string(object.transport), d);
416     }
buildObjectandroid::vintf::TransportArchConverter417     bool buildObject(TransportArch* object, NodeType* root, std::string* error) const override {
418         if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, error) ||
419             !parseText(root, &object->transport, error)) {
420             return false;
421         }
422         if (!object->isValid()) {
423             *error = "transport == " + ::android::vintf::to_string(object->transport) +
424                      " and arch == " + ::android::vintf::to_string(object->arch) +
425                      " is not a valid combination.";
426             return false;
427         }
428         return true;
429     }
430 };
431 
432 TransportArchConverter transportArchConverter{};
433 
434 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
elementNameandroid::vintf::KernelConfigTypedValueConverter435     std::string elementName() const override { return "value"; }
mutateNodeandroid::vintf::KernelConfigTypedValueConverter436     void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override {
437         appendAttr(root, "type", object.mType);
438         appendText(root, ::android::vintf::to_string(object), d);
439     }
buildObjectandroid::vintf::KernelConfigTypedValueConverter440     bool buildObject(KernelConfigTypedValue* object, NodeType* root,
441                      std::string* error) const override {
442         std::string stringValue;
443         if (!parseAttr(root, "type", &object->mType, error) ||
444             !parseText(root, &stringValue, error)) {
445             return false;
446         }
447         if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
448             *error = "Could not parse kernel config value \"" + stringValue + "\"";
449             return false;
450         }
451         return true;
452     }
453 };
454 
455 KernelConfigTypedValueConverter kernelConfigTypedValueConverter{};
456 
457 struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
elementNameandroid::vintf::KernelConfigConverter458     std::string elementName() const override { return "config"; }
mutateNodeandroid::vintf::KernelConfigConverter459     void mutateNode(const KernelConfig &object, NodeType *root, DocType *d) const override {
460         appendChild(root, kernelConfigKeyConverter(object.first, d));
461         appendChild(root, kernelConfigTypedValueConverter(object.second, d));
462     }
buildObjectandroid::vintf::KernelConfigConverter463     bool buildObject(KernelConfig* object, NodeType* root, std::string* error) const override {
464         if (!parseChild(root, kernelConfigKeyConverter, &object->first, error) ||
465             !parseChild(root, kernelConfigTypedValueConverter, &object->second, error)) {
466             return false;
467         }
468         return true;
469     }
470 };
471 
472 KernelConfigConverter kernelConfigConverter{};
473 
474 struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
elementNameandroid::vintf::HalInterfaceConverter475     std::string elementName() const override { return "interface"; }
mutateNodeandroid::vintf::HalInterfaceConverter476     void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override {
477         appendTextElement(root, "name", intf.name(), d);
478         appendTextElements(root, "instance", intf.mInstances, d);
479         appendTextElements(root, "regex-instance", intf.mRegexes, d);
480     }
buildObjectandroid::vintf::HalInterfaceConverter481     bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override {
482         std::vector<std::string> instances;
483         std::vector<std::string> regexes;
484         if (!parseTextElement(root, "name", &intf->mName, error) ||
485             !parseTextElements(root, "instance", &instances, error) ||
486             !parseTextElements(root, "regex-instance", &regexes, error)) {
487             return false;
488         }
489         bool success = true;
490         for (const auto& e : instances) {
491             if (!intf->insertInstance(e, false /* isRegex */)) {
492                 if (!error->empty()) *error += "\n";
493                 *error += "Duplicated instance '" + e + "' in " + intf->name();
494                 success = false;
495             }
496         }
497         for (const auto& e : regexes) {
498             details::Regex regex;
499             if (!regex.compile(e)) {
500                 if (!error->empty()) *error += "\n";
501                 *error += "Invalid regular expression '" + e + "' in " + intf->name();
502                 success = false;
503             }
504             if (!intf->insertInstance(e, true /* isRegex */)) {
505                 if (!error->empty()) *error += "\n";
506                 *error += "Duplicated regex-instance '" + e + "' in " + intf->name();
507                 success = false;
508             }
509         }
510         return success;
511     }
512 };
513 
514 HalInterfaceConverter halInterfaceConverter{};
515 
516 struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
elementNameandroid::vintf::MatrixHalConverter517     std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::MatrixHalConverter518     void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override {
519         appendAttr(root, "format", hal.format);
520         appendAttr(root, "optional", hal.optional);
521         appendTextElement(root, "name", hal.name, d);
522         appendChildren(root, versionRangeConverter, hal.versionRanges, d);
523         appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d);
524     }
buildObjectandroid::vintf::MatrixHalConverter525     bool buildObject(MatrixHal* object, NodeType* root, std::string* error) const override {
526         std::vector<HalInterface> interfaces;
527         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) ||
528             !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional,
529                                error) ||
530             !parseTextElement(root, "name", &object->name, error) ||
531             !parseChildren(root, versionRangeConverter, &object->versionRanges, error) ||
532             !parseChildren(root, halInterfaceConverter, &interfaces, error)) {
533             return false;
534         }
535         for (auto&& interface : interfaces) {
536             std::string name{interface.name()};
537             auto res = object->interfaces.emplace(std::move(name), std::move(interface));
538             if (!res.second) {
539                 *error = "Duplicated interface entry \"" + res.first->first +
540                          "\"; if additional instances are needed, add them to the "
541                          "existing <interface> node.";
542                 return false;
543             }
544         }
545 // Do not check for target-side libvintf to avoid restricting ability for upgrade accidentally.
546 #ifndef LIBVINTF_TARGET
547         if (!checkAdditionalRestrictionsOnHal(*object, error)) {
548             return false;
549         }
550 #endif
551         return true;
552     }
553 
554 #ifndef LIBVINTF_TARGET
555    private:
checkAdditionalRestrictionsOnHalandroid::vintf::MatrixHalConverter556     bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal, std::string* error) const {
557         if (hal.getName() == "netutils-wrapper") {
558             if (hal.versionRanges.size() != 1) {
559                 *error =
560                     "netutils-wrapper HAL must specify exactly one version x.0, "
561                     "but multiple <version> element is specified.";
562                 return false;
563             }
564             const VersionRange& v = hal.versionRanges.at(0);
565             if (!v.isSingleVersion()) {
566                 *error =
567                     "netutils-wrapper HAL must specify exactly one version x.0, "
568                     "but a range is provided. Perhaps you mean '" +
569                     to_string(Version{v.majorVer, 0}) + "'?";
570                 return false;
571             }
572             if (v.minMinor != 0) {
573                 *error =
574                     "netutils-wrapper HAL must specify exactly one version x.0, "
575                     "but minor version is not 0. Perhaps you mean '" +
576                     to_string(Version{v.majorVer, 0}) + "'?";
577                 return false;
578             }
579         }
580         return true;
581     }
582 #endif
583 };
584 
585 MatrixHalConverter matrixHalConverter{};
586 
587 struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> {
elementNameandroid::vintf::MatrixKernelConditionsConverter588     std::string elementName() const override { return "conditions"; }
mutateNodeandroid::vintf::MatrixKernelConditionsConverter589     void mutateNode(const std::vector<KernelConfig>& conds, NodeType* root,
590                     DocType* d) const override {
591         appendChildren(root, kernelConfigConverter, conds, d);
592     }
buildObjectandroid::vintf::MatrixKernelConditionsConverter593     bool buildObject(std::vector<KernelConfig>* object, NodeType* root,
594                      std::string* error) const override {
595         return parseChildren(root, kernelConfigConverter, object, error);
596     }
597 };
598 
599 MatrixKernelConditionsConverter matrixKernelConditionsConverter{};
600 
601 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
elementNameandroid::vintf::MatrixKernelConverter602     std::string elementName() const override { return "kernel"; }
mutateNodeandroid::vintf::MatrixKernelConverter603     void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override {
604         appendAttr(root, "version", kernel.mMinLts);
605         if (!kernel.mConditions.empty()) {
606             appendChild(root, matrixKernelConditionsConverter(kernel.mConditions, d));
607         }
608         appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
609     }
buildObjectandroid::vintf::MatrixKernelConverter610     bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override {
611         if (!parseAttr(root, "version", &object->mMinLts, error) ||
612             !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions,
613                                 error) ||
614             !parseChildren(root, kernelConfigConverter, &object->mConfigs, error)) {
615             return false;
616         }
617         return true;
618     }
619 };
620 
621 MatrixKernelConverter matrixKernelConverter{};
622 
623 XmlTextConverter<FqInstance> fqInstanceConverter{"fqname"};
624 
625 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
elementNameandroid::vintf::ManifestHalConverter626     std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::ManifestHalConverter627     void mutateNode(const ManifestHal& m, NodeType* root, DocType* d) const override {
628         mutateNode(m, root, d, SerializeFlag::EVERYTHING);
629     }
mutateNodeandroid::vintf::ManifestHalConverter630     void mutateNode(const ManifestHal& hal, NodeType* root, DocType* d,
631                     SerializeFlags flags) const override {
632         appendAttr(root, "format", hal.format);
633         appendTextElement(root, "name", hal.name, d);
634         appendChild(root, transportArchConverter(hal.transportArch, d));
635         appendChildren(root, versionConverter, hal.versions, d);
636         appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d);
637         if (hal.isOverride()) {
638             appendAttr(root, "override", hal.isOverride());
639         }
640 
641         if (!(flags & SerializeFlag::NO_FQNAME)) {
642             std::set<FqInstance> fqInstances;
643             hal.forEachInstance([&fqInstances](const auto& manifestInstance) {
644                 fqInstances.emplace(manifestInstance.getFqInstanceNoPackage());
645                 return true;
646             });
647             appendChildren(root, fqInstanceConverter, fqInstances, d);
648         }
649     }
buildObjectandroid::vintf::ManifestHalConverter650     bool buildObject(ManifestHal* object, NodeType* root, std::string* error) const override {
651         std::vector<HalInterface> interfaces;
652         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) ||
653             !parseOptionalAttr(root, "override", false, &object->mIsOverride, error) ||
654             !parseTextElement(root, "name", &object->name, error) ||
655             !parseOptionalChild(root, transportArchConverter, {}, &object->transportArch, error) ||
656             !parseChildren(root, versionConverter, &object->versions, error) ||
657             !parseChildren(root, halInterfaceConverter, &interfaces, error)) {
658             return false;
659         }
660 
661         switch (object->format) {
662             case HalFormat::HIDL: {
663                 if (object->transportArch.empty()) {
664                     *error = "HIDL HAL '" + object->name + "' should have <transport> defined.";
665                     return false;
666                 }
667             } break;
668             case HalFormat::NATIVE: {
669                 if (!object->transportArch.empty()) {
670                     *error =
671                         "Native HAL '" + object->name + "' should not have <transport> defined.";
672                     return false;
673                 }
674             } break;
675             default: {
676                 LOG(FATAL) << "Unhandled HalFormat "
677                            << static_cast<typename std::underlying_type<HalFormat>::type>(
678                                   object->format);
679             } break;
680         }
681         if (!object->transportArch.isValid()) return false;
682 
683         object->interfaces.clear();
684         for (auto &&interface : interfaces) {
685             auto res = object->interfaces.emplace(interface.name(), std::move(interface));
686             if (!res.second) {
687                 *error = "Duplicated interface entry \"" + res.first->first +
688                          "\"; if additional instances are needed, add them to the "
689                          "existing <interface> node.";
690                 return false;
691             }
692         }
693         if (!object->isValid()) {
694             *error = "'" + object->name + "' is not a valid Manifest HAL.";
695             return false;
696         }
697 // Do not check for target-side libvintf to avoid restricting upgrade accidentally.
698 #ifndef LIBVINTF_TARGET
699         if (!checkAdditionalRestrictionsOnHal(*object, error)) {
700             return false;
701         }
702 #endif
703 
704         std::set<FqInstance> fqInstances;
705         if (!parseChildren(root, fqInstanceConverter, &fqInstances, error)) {
706             return false;
707         }
708         if (!object->insertInstances(fqInstances, error)) {
709             return false;
710         }
711 
712         return true;
713     }
714 
715 #ifndef LIBVINTF_TARGET
716    private:
checkAdditionalRestrictionsOnHalandroid::vintf::ManifestHalConverter717     bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal, std::string* error) const {
718         if (hal.getName() == "netutils-wrapper") {
719             for (const Version& v : hal.versions) {
720                 if (v.minorVer != 0) {
721                     *error =
722                         "netutils-wrapper HAL must specify exactly one version x.0, "
723                         "but minor version is not 0. Perhaps you mean '" +
724                         to_string(Version{v.majorVer, 0}) + "'?";
725                     return false;
726                 }
727             }
728         }
729         return true;
730     }
731 #endif
732 };
733 
734 // Convert ManifestHal from and to XML. Returned object is guaranteed to have
735 // .isValid() == true.
736 ManifestHalConverter manifestHalConverter{};
737 
738 XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"};
739 XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"};
740 
741 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
elementNameandroid::vintf::SepolicyConverter742     std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::SepolicyConverter743     void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override {
744         appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d));
745         appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d);
746     }
buildObjectandroid::vintf::SepolicyConverter747     bool buildObject(Sepolicy* object, NodeType* root, std::string* error) const override {
748         if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion,
749                         error) ||
750             !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges,
751                            error)) {
752             return false;
753         }
754         return true;
755     }
756 };
757 SepolicyConverter sepolicyConverter{};
758 
759 [[deprecated]] XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"};
760 
761 XmlTextConverter<std::string> vndkVersionConverter{"version"};
762 XmlTextConverter<std::string> vndkLibraryConverter{"library"};
763 
764 struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> {
elementNameandroid::vintf::VndkConverter765     std::string elementName() const override { return "vndk"; }
mutateNodeandroid::vintf::VndkConverter766     void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override {
767         appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d));
768         appendChildren(root, vndkLibraryConverter, object.mLibraries, d);
769     }
buildObjectandroid::vintf::VndkConverter770     bool buildObject(Vndk* object, NodeType* root, std::string* error) const override {
771         if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange, error) ||
772             !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) {
773             return false;
774         }
775         return true;
776     }
777 };
778 
779 [[deprecated]] VndkConverter vndkConverter{};
780 
781 struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> {
elementNameandroid::vintf::VendorNdkConverter782     std::string elementName() const override { return "vendor-ndk"; }
mutateNodeandroid::vintf::VendorNdkConverter783     void mutateNode(const VendorNdk& object, NodeType* root, DocType* d) const override {
784         appendChild(root, vndkVersionConverter(object.mVersion, d));
785         appendChildren(root, vndkLibraryConverter, object.mLibraries, d);
786     }
buildObjectandroid::vintf::VendorNdkConverter787     bool buildObject(VendorNdk* object, NodeType* root, std::string* error) const override {
788         if (!parseChild(root, vndkVersionConverter, &object->mVersion, error) ||
789             !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) {
790             return false;
791         }
792         return true;
793     }
794 };
795 
796 VendorNdkConverter vendorNdkConverter{};
797 
798 XmlTextConverter<std::string> systemSdkVersionConverter{"version"};
799 
800 struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> {
elementNameandroid::vintf::SystemSdkConverter801     std::string elementName() const override { return "system-sdk"; }
mutateNodeandroid::vintf::SystemSdkConverter802     void mutateNode(const SystemSdk& object, NodeType* root, DocType* d) const override {
803         appendChildren(root, systemSdkVersionConverter, object.versions(), d);
804     }
buildObjectandroid::vintf::SystemSdkConverter805     bool buildObject(SystemSdk* object, NodeType* root, std::string* error) const override {
806         return parseChildren(root, systemSdkVersionConverter, &object->mVersions, error);
807     }
808 };
809 
810 SystemSdkConverter systemSdkConverter{};
811 
812 struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::HalManifestSepolicyConverter813     std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::HalManifestSepolicyConverter814     void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
815         appendChild(root, versionConverter(m, d));
816     }
buildObjectandroid::vintf::HalManifestSepolicyConverter817     bool buildObject(Version* object, NodeType* root, std::string* error) const override {
818         return parseChild(root, versionConverter, object, error);
819     }
820 };
821 HalManifestSepolicyConverter halManifestSepolicyConverter{};
822 
823 struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> {
elementNameandroid::vintf::ManifestXmlFileConverter824     std::string elementName() const override { return "xmlfile"; }
mutateNodeandroid::vintf::ManifestXmlFileConverter825     void mutateNode(const ManifestXmlFile& f, NodeType* root, DocType* d) const override {
826         appendTextElement(root, "name", f.name(), d);
827         appendChild(root, versionConverter(f.version(), d));
828         if (!f.overriddenPath().empty()) {
829             appendTextElement(root, "path", f.overriddenPath(), d);
830         }
831     }
buildObjectandroid::vintf::ManifestXmlFileConverter832     bool buildObject(ManifestXmlFile* object, NodeType* root, std::string* error) const override {
833         if (!parseTextElement(root, "name", &object->mName, error) ||
834             !parseChild(root, versionConverter, &object->mVersion, error) ||
835             !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) {
836             return false;
837         }
838         return true;
839     }
840 };
841 ManifestXmlFileConverter manifestXmlFileConverter{};
842 
843 struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
elementNameandroid::vintf::HalManifestConverter844     std::string elementName() const override { return "manifest"; }
mutateNodeandroid::vintf::HalManifestConverter845     void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override {
846         mutateNode(m, root, d, SerializeFlag::EVERYTHING);
847     }
mutateNodeandroid::vintf::HalManifestConverter848     void mutateNode(const HalManifest& m, NodeType* root, DocType* d,
849                     SerializeFlags flags) const override {
850         appendAttr(root, "version", m.getMetaVersion());
851         appendAttr(root, "type", m.mType);
852 
853         if (!(flags & SerializeFlag::NO_HALS)) {
854             appendChildren(root, manifestHalConverter, m.getHals(), d, flags);
855         }
856         if (m.mType == SchemaType::DEVICE) {
857             if (!(flags & SerializeFlag::NO_SEPOLICY)) {
858                 appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
859             }
860             if (m.mLevel != Level::UNSPECIFIED) {
861                 this->appendAttr(root, "target-level", m.mLevel);
862             }
863         } else if (m.mType == SchemaType::FRAMEWORK) {
864             if (!(flags & SerializeFlag::NO_VNDK)) {
865 #pragma clang diagnostic push
866 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
867                 appendChildren(root, vndkConverter, m.framework.mVndks, d);
868 #pragma clang diagnostic pop
869 
870                 appendChildren(root, vendorNdkConverter, m.framework.mVendorNdks, d);
871             }
872             if (!(flags & SerializeFlag::NO_SSDK)) {
873                 if (!m.framework.mSystemSdk.empty()) {
874                     appendChild(root, systemSdkConverter(m.framework.mSystemSdk, d));
875                 }
876             }
877         }
878 
879         if (!(flags & SerializeFlag::NO_XMLFILES)) {
880             appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d);
881         }
882     }
buildObjectandroid::vintf::HalManifestConverter883     bool buildObject(HalManifest* object, NodeType* root, std::string* error) const override {
884         std::vector<ManifestHal> hals;
885         if (!parseAttr(root, "version", &object->mMetaVersion, error) ||
886             !parseAttr(root, "type", &object->mType, error) ||
887             !parseChildren(root, manifestHalConverter, &hals, error)) {
888             return false;
889         }
890         if (!kMetaVersion.minorAtLeast(object->mMetaVersion)) {
891             *error = "Unrecognized manifest.version " + to_string(object->mMetaVersion) +
892                      " (libvintf@" + to_string(kMetaVersion) + ")";
893             return false;
894         }
895         if (object->mType == SchemaType::DEVICE) {
896             // tags for device hal manifest only.
897             // <sepolicy> can be missing because it can be determined at build time, not hard-coded
898             // in the XML file.
899             if (!parseOptionalChild(root, halManifestSepolicyConverter, {},
900                                     &object->device.mSepolicyVersion, error)) {
901                 return false;
902             }
903 
904             if (!parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
905                                    error)) {
906                 return false;
907             }
908         } else if (object->mType == SchemaType::FRAMEWORK) {
909 #pragma clang diagnostic push
910 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
911             if (!parseChildren(root, vndkConverter, &object->framework.mVndks, error)) {
912                 return false;
913             }
914             for (const auto &vndk : object->framework.mVndks) {
915                 if (!vndk.mVersionRange.isSingleVersion()) {
916                     *error = "vndk.version " + to_string(vndk.mVersionRange) +
917                              " cannot be a range for manifests";
918                     return false;
919                 }
920             }
921 #pragma clang diagnostic pop
922 
923             if (!parseChildren(root, vendorNdkConverter, &object->framework.mVendorNdks, error)) {
924                 return false;
925             }
926 
927             std::set<std::string> vendorNdkVersions;
928             for (const auto& vendorNdk : object->framework.mVendorNdks) {
929                 if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) {
930                     *error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version();
931                     return false;
932                 }
933                 vendorNdkVersions.insert(vendorNdk.version());
934             }
935 
936             if (!parseOptionalChild(root, systemSdkConverter, {}, &object->framework.mSystemSdk,
937                                     error)) {
938                 return false;
939             }
940         }
941         for (auto &&hal : hals) {
942             std::string description{hal.name};
943             if (!object->add(std::move(hal))) {
944                 *error = "Duplicated manifest.hal entry " + description;
945                 return false;
946             }
947         }
948 
949         std::vector<ManifestXmlFile> xmlFiles;
950         if (!parseChildren(root, manifestXmlFileConverter, &xmlFiles, error)) {
951             return false;
952         }
953         for (auto&& xmlFile : xmlFiles) {
954             std::string description{xmlFile.name()};
955             if (!object->addXmlFile(std::move(xmlFile))) {
956                 *error = "Duplicated manifest.xmlfile entry " + description +
957                          "; entries cannot have duplicated name and version";
958                 return false;
959             }
960         }
961 
962         return true;
963     }
964 };
965 
966 HalManifestConverter halManifestConverter{};
967 
968 XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"};
969 struct AvbConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::AvbConverter970     std::string elementName() const override { return "avb"; }
mutateNodeandroid::vintf::AvbConverter971     void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
972         appendChild(root, avbVersionConverter(m, d));
973     }
buildObjectandroid::vintf::AvbConverter974     bool buildObject(Version* object, NodeType* root, std::string* error) const override {
975         return parseChild(root, avbVersionConverter, object, error);
976     }
977 };
978 AvbConverter avbConverter{};
979 
980 struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> {
elementNameandroid::vintf::MatrixXmlFileConverter981     std::string elementName() const override { return "xmlfile"; }
mutateNodeandroid::vintf::MatrixXmlFileConverter982     void mutateNode(const MatrixXmlFile& f, NodeType* root, DocType* d) const override {
983         appendTextElement(root, "name", f.name(), d);
984         appendAttr(root, "format", f.format());
985         appendAttr(root, "optional", f.optional());
986         appendChild(root, versionRangeConverter(f.versionRange(), d));
987         if (!f.overriddenPath().empty()) {
988             appendTextElement(root, "path", f.overriddenPath(), d);
989         }
990     }
buildObjectandroid::vintf::MatrixXmlFileConverter991     bool buildObject(MatrixXmlFile* object, NodeType* root, std::string* error) const override {
992         if (!parseTextElement(root, "name", &object->mName, error) ||
993             !parseAttr(root, "format", &object->mFormat, error) ||
994             !parseOptionalAttr(root, "optional", false, &object->mOptional, error) ||
995             !parseChild(root, versionRangeConverter, &object->mVersionRange, error) ||
996             !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) {
997             return false;
998         }
999         return true;
1000     }
1001 };
1002 MatrixXmlFileConverter matrixXmlFileConverter{};
1003 
1004 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
elementNameandroid::vintf::CompatibilityMatrixConverter1005     std::string elementName() const override { return "compatibility-matrix"; }
mutateNodeandroid::vintf::CompatibilityMatrixConverter1006     void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override {
1007         mutateNode(m, root, d, SerializeFlag::EVERYTHING);
1008     }
mutateNodeandroid::vintf::CompatibilityMatrixConverter1009     void mutateNode(const CompatibilityMatrix& m, NodeType* root, DocType* d,
1010                     SerializeFlags flags) const override {
1011         appendAttr(root, "version", m.getMinimumMetaVersion());
1012         appendAttr(root, "type", m.mType);
1013 
1014         if (!(flags & SerializeFlag::NO_HALS)) {
1015             appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d);
1016         }
1017         if (m.mType == SchemaType::FRAMEWORK) {
1018             if (!(flags & SerializeFlag::NO_KERNEL)) {
1019                 appendChildren(root, matrixKernelConverter, m.framework.mKernels, d);
1020             }
1021             if (!(flags & SerializeFlag::NO_SEPOLICY)) {
1022                 if (!(m.framework.mSepolicy == Sepolicy{})) {
1023                     appendChild(root, sepolicyConverter(m.framework.mSepolicy, d));
1024                 }
1025             }
1026             if (!(flags & SerializeFlag::NO_AVB)) {
1027                 if (!(m.framework.mAvbMetaVersion == Version{})) {
1028                     appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d));
1029                 }
1030             }
1031             if (m.mLevel != Level::UNSPECIFIED) {
1032                 this->appendAttr(root, "level", m.mLevel);
1033             }
1034         } else if (m.mType == SchemaType::DEVICE) {
1035             if (!(flags & SerializeFlag::NO_VNDK)) {
1036 #pragma clang diagnostic push
1037 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1038                 if (!(m.device.mVndk == Vndk{})) {
1039                     appendChild(root, vndkConverter(m.device.mVndk, d));
1040                 }
1041 #pragma clang diagnostic pop
1042 
1043                 if (!(m.device.mVendorNdk == VendorNdk{})) {
1044                     appendChild(root, vendorNdkConverter(m.device.mVendorNdk, d));
1045                 }
1046             }
1047 
1048             if (!(flags & SerializeFlag::NO_SSDK)) {
1049                 if (!m.device.mSystemSdk.empty()) {
1050                     appendChild(root, systemSdkConverter(m.device.mSystemSdk, d));
1051                 }
1052             }
1053         }
1054 
1055         if (!(flags & SerializeFlag::NO_XMLFILES)) {
1056             appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d);
1057         }
1058     }
buildObjectandroid::vintf::CompatibilityMatrixConverter1059     bool buildObject(CompatibilityMatrix* object, NodeType* root,
1060                      std::string* error) const override {
1061         Version version;
1062         std::vector<MatrixHal> hals;
1063         if (!parseAttr(root, "version", &version, error) ||
1064             !parseAttr(root, "type", &object->mType, error) ||
1065             !parseChildren(root, matrixHalConverter, &hals, error)) {
1066             return false;
1067         }
1068 
1069         if (object->mType == SchemaType::FRAMEWORK) {
1070             // <avb> and <sepolicy> can be missing because it can be determined at build time, not
1071             // hard-coded in the XML file.
1072             if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels, error) ||
1073                 !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy,
1074                                     error) ||
1075                 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion,
1076                                     error)) {
1077                 return false;
1078             }
1079 
1080             std::set<Version> seenKernelVersions;
1081             for (const auto& kernel : object->framework.mKernels) {
1082                 Version minLts(kernel.minLts().version, kernel.minLts().majorRev);
1083                 if (seenKernelVersions.find(minLts) != seenKernelVersions.end()) {
1084                     continue;
1085                 }
1086                 if (!kernel.conditions().empty()) {
1087                     *error = "First <kernel> for version " + to_string(minLts) +
1088                              " must have empty <conditions> for backwards compatibility.";
1089                     return false;
1090                 }
1091                 seenKernelVersions.insert(minLts);
1092             }
1093 
1094             if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel, error)) {
1095                 return false;
1096             }
1097 
1098         } else if (object->mType == SchemaType::DEVICE) {
1099             // <vndk> can be missing because it can be determined at build time, not hard-coded
1100             // in the XML file.
1101 #pragma clang diagnostic push
1102 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1103             if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk, error)) {
1104                 return false;
1105             }
1106 #pragma clang diagnostic pop
1107 
1108             if (!parseOptionalChild(root, vendorNdkConverter, {}, &object->device.mVendorNdk,
1109                                     error)) {
1110                 return false;
1111             }
1112 
1113             if (!parseOptionalChild(root, systemSdkConverter, {}, &object->device.mSystemSdk,
1114                                     error)) {
1115                 return false;
1116             }
1117         }
1118 
1119         if (!kMetaVersion.minorAtLeast(version)) {
1120             *error = "Unrecognized compatibility-matrix.version " + to_string(version) +
1121                      " (libvintf@" + to_string(kMetaVersion) + ")";
1122             return false;
1123         }
1124         for (auto &&hal : hals) {
1125             if (!object->add(std::move(hal))) {
1126                 *error = "Duplicated compatibility-matrix.hal entry";
1127                 return false;
1128             }
1129         }
1130 
1131         std::vector<MatrixXmlFile> xmlFiles;
1132         if (!parseChildren(root, matrixXmlFileConverter, &xmlFiles, error)) {
1133             return false;
1134         }
1135         for (auto&& xmlFile : xmlFiles) {
1136             if (!xmlFile.optional()) {
1137                 *error = "compatibility-matrix.xmlfile entry " + xmlFile.name() +
1138                          " has to be optional for compatibility matrix version 1.0";
1139                 return false;
1140             }
1141             std::string description{xmlFile.name()};
1142             if (!object->addXmlFile(std::move(xmlFile))) {
1143                 *error = "Duplicated compatibility-matrix.xmlfile entry " + description;
1144                 return false;
1145             }
1146         }
1147 
1148         return true;
1149     }
1150 };
1151 
1152 CompatibilityMatrixConverter compatibilityMatrixConverter{};
1153 
1154 // Publicly available as in parse_xml.h
1155 XmlConverter<HalManifest>& gHalManifestConverter = halManifestConverter;
1156 XmlConverter<CompatibilityMatrix>& gCompatibilityMatrixConverter = compatibilityMatrixConverter;
1157 
1158 // For testing in LibVintfTest
1159 XmlConverter<Version>& gVersionConverter = versionConverter;
1160 XmlConverter<KernelConfigTypedValue>& gKernelConfigTypedValueConverter =
1161     kernelConfigTypedValueConverter;
1162 XmlConverter<MatrixHal>& gMatrixHalConverter = matrixHalConverter;
1163 XmlConverter<ManifestHal>& gManifestHalConverter = manifestHalConverter;
1164 
1165 } // namespace vintf
1166 } // namespace android
1167