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", ®exes, 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