xref: /aosp_15_r20/system/libvintf/parse_xml.cpp (revision 70a7ec852fcefd15a4fb57f8f183a8b1c3aacb08)
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 <android-base/parseint.h>
27 #include <android-base/strings.h>
28 #include <tinyxml2.h>
29 
30 #include "Regex.h"
31 #include "constants-private.h"
32 #include "constants.h"
33 #include "parse_string.h"
34 #include "parse_xml_for_test.h"
35 #include "utils.h"
36 
37 using namespace std::string_literals;
38 
39 #ifdef LIBVINTF_TARGET
40 static constexpr bool kDevice = true;
41 #else
42 static constexpr bool kDevice = false;
43 #endif
44 
45 namespace android {
46 namespace vintf {
47 
48 // --------------- tinyxml2 details
49 
50 using NodeType = tinyxml2::XMLElement;
51 using DocType = tinyxml2::XMLDocument;
52 
53 // caller is responsible for deleteDocument() call
createDocument()54 inline DocType *createDocument() {
55     return new tinyxml2::XMLDocument();
56 }
57 
58 // caller is responsible for deleteDocument() call
createDocument(const std::string & xml)59 inline DocType *createDocument(const std::string &xml) {
60     DocType *doc = new tinyxml2::XMLDocument();
61     if (doc->Parse(xml.c_str()) == tinyxml2::XML_SUCCESS) {
62         return doc;
63     }
64     delete doc;
65     return nullptr;
66 }
67 
deleteDocument(DocType * d)68 inline void deleteDocument(DocType *d) {
69     delete d;
70 }
71 
printDocument(DocType * d)72 inline std::string printDocument(DocType *d) {
73     tinyxml2::XMLPrinter p;
74     d->Print(&p);
75     return std::string{p.CStr()};
76 }
77 
createNode(const std::string & name,DocType * d)78 inline NodeType *createNode(const std::string &name, DocType *d) {
79     return d->NewElement(name.c_str());
80 }
81 
appendChild(NodeType * parent,NodeType * child)82 inline void appendChild(NodeType *parent, NodeType *child) {
83     parent->InsertEndChild(child);
84 }
85 
appendChild(DocType * parent,NodeType * child)86 inline void appendChild(DocType *parent, NodeType *child) {
87     parent->InsertEndChild(child);
88 }
89 
appendStrAttr(NodeType * e,const std::string & attrName,const std::string & attr)90 inline void appendStrAttr(NodeType *e, const std::string &attrName, const std::string &attr) {
91     e->SetAttribute(attrName.c_str(), attr.c_str());
92 }
93 
94 // text -> text
appendText(NodeType * parent,const std::string & text,DocType * d)95 inline void appendText(NodeType *parent, const std::string &text, DocType *d) {
96     parent->InsertEndChild(d->NewText(text.c_str()));
97 }
98 
nameOf(NodeType * root)99 inline std::string nameOf(NodeType *root) {
100     return root->Name() == NULL ? "" : root->Name();
101 }
102 
getText(NodeType * root)103 inline std::string getText(NodeType *root) {
104     return root->GetText() == NULL ? "" : root->GetText();
105 }
106 
getChild(NodeType * parent,const std::string & name)107 inline NodeType *getChild(NodeType *parent, const std::string &name) {
108     return parent->FirstChildElement(name.c_str());
109 }
110 
getRootChild(DocType * parent)111 inline NodeType *getRootChild(DocType *parent) {
112     return parent->FirstChildElement();
113 }
114 
getChildren(NodeType * parent,const std::string & name)115 inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) {
116     std::vector<NodeType *> v;
117     for (NodeType *child = parent->FirstChildElement(name.c_str());
118          child != nullptr;
119          child = child->NextSiblingElement(name.c_str())) {
120         v.push_back(child);
121     }
122     return v;
123 }
124 
getAttr(NodeType * root,const std::string & attrName,std::string * s)125 inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) {
126     const char *c = root->Attribute(attrName.c_str());
127     if (c == NULL)
128         return false;
129     *s = c;
130     return true;
131 }
132 
133 // --------------- tinyxml2 details end.
134 
135 // Helper functions for XmlConverter
parse(const std::string & attrText,bool * attr)136 static bool parse(const std::string &attrText, bool *attr) {
137     if (attrText == "true" || attrText == "1") {
138         *attr = true;
139         return true;
140     }
141     if (attrText == "false" || attrText == "0") {
142         *attr = false;
143         return true;
144     }
145     return false;
146 }
147 
parse(const std::string & attrText,std::optional<std::string> * attr)148 static bool parse(const std::string& attrText, std::optional<std::string>* attr) {
149     *attr = attrText;
150     return true;
151 }
152 
parse(const std::string & s,std::optional<uint64_t> * out)153 static bool parse(const std::string& s, std::optional<uint64_t>* out) {
154     uint64_t val;
155     if (base::ParseUint(s, &val)) {
156         *out = val;
157         return true;
158     }
159     return false;
160 }
161 
162 // ---------------------- XmlNodeConverter definitions
163 
164 // When serializing an object to an XML document, these parameters don't change until
165 // the object is fully serialized.
166 // These parameters are also passed to converters of child nodes so they see the same
167 // serialization parameters.
168 struct MutateNodeParam {
169     DocType* d;
170     SerializeFlags::Type flags = SerializeFlags::EVERYTHING;
171 };
172 
173 // When deserializing an XML document to an object, these parameters don't change until
174 // the XML document is fully deserialized.
175 // * Except metaVersion, which is immediately modified when parsing top-level <manifest>
176 //   or <compatibility-matrix>, and unchanged thereafter;
177 //   see HalManifestConverter::BuildObject and CompatibilityMatrixConverter::BuildObject)
178 // These parameters are also passed to converters of child nodes so they see the same
179 // deserialization parameters.
180 struct BuildObjectParam {
181     std::string* error;
182     Version metaVersion;
183     std::string fileName;
184 };
185 
186 template <typename Object>
187 struct XmlNodeConverter {
XmlNodeConverterandroid::vintf::XmlNodeConverter188     XmlNodeConverter() {}
~XmlNodeConverterandroid::vintf::XmlNodeConverter189     virtual ~XmlNodeConverter() {}
190 
191    protected:
192     virtual void mutateNode(const Object& object, NodeType* root, const MutateNodeParam&) const = 0;
193     virtual bool buildObject(Object* object, NodeType* root, const BuildObjectParam&) const = 0;
194 
195    public:
196     // Methods for other (usually parent) converters
197     // Name of the XML element.
198     virtual std::string elementName() const = 0;
199     // Serialize |o| into an XML element.
operator ()android::vintf::XmlNodeConverter200     inline NodeType* operator()(const Object& o, const MutateNodeParam& param) const {
201         NodeType* root = createNode(this->elementName(), param.d);
202         this->mutateNode(o, root, param);
203         return root;
204     }
205     // Deserialize XML element |root| into |object|.
operator ()android::vintf::XmlNodeConverter206     inline bool operator()(Object* object, NodeType* root, const BuildObjectParam& param) const {
207         if (nameOf(root) != this->elementName()) {
208             *param.error = "The root name(" + nameOf(root) + ") does not match the element name (" +
209                            this->elementName() + ")";
210             return false;
211         }
212         return this->buildObject(object, root, param);
213     }
214 
215     // Public methods for android::vintf::fromXml / android::vintf::toXml.
216     // Serialize |o| into an XML string.
toXmlandroid::vintf::XmlNodeConverter217     inline std::string toXml(const Object& o, SerializeFlags::Type flags) const {
218         DocType* doc = createDocument();
219         appendChild(doc, (*this)(o, MutateNodeParam{doc, flags}));
220         std::string s = printDocument(doc);
221         deleteDocument(doc);
222         return s;
223     }
224     // Deserialize XML string |xml| into |o|.
fromXmlandroid::vintf::XmlNodeConverter225     inline bool fromXml(Object* o, const std::string& xml, std::string* error) const {
226         std::string errorBuffer;
227         if (error == nullptr) error = &errorBuffer;
228 
229         auto doc = createDocument(xml);
230         if (doc == nullptr) {
231             *error = "Not a valid XML";
232             return false;
233         }
234         // For top-level <manifest> and <compatibility-matrix>, HalManifestConverter and
235         // CompatibilityMatrixConverter fills in metaversion and pass down to children.
236         // For other nodes, we don't know metaversion of the original XML, so just leave empty
237         // for maximum backwards compatibility.
238         BuildObjectParam buildObjectParam{error, {}, {}};
239         // Pass down filename for the current XML document.
240         if constexpr (std::is_base_of_v<WithFileName, Object>) {
241             // Get the last filename in case `o` keeps the list of filenames
242             std::string_view fileName{o->fileName()};
243             if (auto pos = fileName.rfind(':'); pos != fileName.npos) {
244                 fileName.remove_prefix(pos + 1);
245             }
246             buildObjectParam.fileName = std::string(fileName);
247         }
248         bool ret = (*this)(o, getRootChild(doc), buildObjectParam);
249         deleteDocument(doc);
250         return ret;
251     }
252 
253     // convenience methods for subclasses to implement virtual functions.
254 
255     // All append* functions helps mutateNode() to serialize the object into XML.
256     template <typename T>
appendAttrandroid::vintf::XmlNodeConverter257     inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const {
258         return appendStrAttr(e, attrName, ::android::vintf::to_string(attr));
259     }
260 
appendAttrandroid::vintf::XmlNodeConverter261     inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const {
262         return appendStrAttr(e, attrName, attr ? "true" : "false");
263     }
264 
265     // text -> <name>text</name>
appendTextElementandroid::vintf::XmlNodeConverter266     inline void appendTextElement(NodeType *parent, const std::string &name,
267                 const std::string &text, DocType *d) const {
268         NodeType *c = createNode(name, d);
269         appendText(c, text, d);
270         appendChild(parent, c);
271     }
272 
273     // text -> <name>text</name>
274     template<typename Array>
appendTextElementsandroid::vintf::XmlNodeConverter275     inline void appendTextElements(NodeType *parent, const std::string &name,
276                 const Array &array, DocType *d) const {
277         for (const std::string &text : array) {
278             NodeType *c = createNode(name, d);
279             appendText(c, text, d);
280             appendChild(parent, c);
281         }
282     }
283 
284     template <typename T, typename Array>
appendChildrenandroid::vintf::XmlNodeConverter285     inline void appendChildren(NodeType* parent, const XmlNodeConverter<T>& conv,
286                                const Array& array, const MutateNodeParam& param) const {
287         for (const T &t : array) {
288             appendChild(parent, conv(t, param));
289         }
290     }
291 
292     // All parse* functions helps buildObject() to deserialize XML to the object. Returns
293     // true if deserialization is successful, false if any error, and "error" will be
294     // set to error message.
295     template <typename T>
parseOptionalAttrandroid::vintf::XmlNodeConverter296     inline bool parseOptionalAttr(NodeType* root, const std::string& attrName, T&& defaultValue,
297                                   T* attr, const BuildObjectParam& param) const {
298         std::string attrText;
299         bool success = getAttr(root, attrName, &attrText);
300         bool parseSuccess = true;
301         if (success) {
302             parseSuccess = ::android::vintf::parse(attrText, attr);
303         } else {
304             *attr = std::move(defaultValue);
305         }
306         if (param.metaVersion >= kMetaVersionStrictAttributeValues) {
307             if (!parseSuccess && param.error) {
308                 *param.error += "Unknown value (\"" + attrText + "\") for attribute '" + attrName +
309                                 "' is considered a failure.";
310             }
311             return parseSuccess;
312         } else {
313             return true;
314         }
315     }
316 
317     template <typename T>
parseAttrandroid::vintf::XmlNodeConverter318     inline bool parseAttr(NodeType* root, const std::string& attrName, T* attr,
319                           std::string* error) const {
320         std::string attrText;
321         bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
322         if (!ret) {
323             *error = "Could not find/parse attr with name \"" + attrName + "\" and value \"" +
324                      attrText + "\" for element <" + elementName() + ">";
325         }
326         return ret;
327     }
328 
parseAttrandroid::vintf::XmlNodeConverter329     inline bool parseAttr(NodeType* root, const std::string& attrName, std::string* attr,
330                           std::string* error) const {
331         bool ret = getAttr(root, attrName, attr);
332         if (!ret) {
333             *error = "Could not find attr with name \"" + attrName + "\" for element <" +
334                      elementName() + ">";
335         }
336         return ret;
337     }
338 
parseTextElementandroid::vintf::XmlNodeConverter339     inline bool parseTextElement(NodeType* root, const std::string& elementName, std::string* s,
340                                  std::string* error) const {
341         NodeType *child = getChild(root, elementName);
342         if (child == nullptr) {
343             *error = "Could not find element with name <" + elementName + "> in element <" +
344                      this->elementName() + ">";
345             return false;
346         }
347         *s = getText(child);
348         return true;
349     }
350 
351     template <typename T>
parseOptionalTextElementandroid::vintf::XmlNodeConverter352     inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName,
353                                          T&& defaultValue, T* s, std::string* /* error */) const {
354         NodeType* child = getChild(root, elementName);
355         *s = child == nullptr ? std::move(defaultValue) : getText(child);
356         return true;
357     }
358 
parseTextElementsandroid::vintf::XmlNodeConverter359     inline bool parseTextElements(NodeType* root, const std::string& elementName,
360                                   std::vector<std::string>* v, std::string* /* error */) const {
361         auto nodes = getChildren(root, elementName);
362         v->resize(nodes.size());
363         for (size_t i = 0; i < nodes.size(); ++i) {
364             v->at(i) = getText(nodes[i]);
365         }
366         return true;
367     }
368 
369     template <typename T>
parseChildandroid::vintf::XmlNodeConverter370     inline bool parseChild(NodeType* root, const XmlNodeConverter<T>& conv, T* t,
371                            const BuildObjectParam& param) const {
372         NodeType *child = getChild(root, conv.elementName());
373         if (child == nullptr) {
374             *param.error = "Could not find element with name <" + conv.elementName() +
375                            "> in element <" + this->elementName() + ">";
376             return false;
377         }
378         return conv(t, child, param);
379     }
380 
381     template <typename T>
parseOptionalChildandroid::vintf::XmlNodeConverter382     inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
383                                    T&& defaultValue, T* t, const BuildObjectParam& param) const {
384         NodeType *child = getChild(root, conv.elementName());
385         if (child == nullptr) {
386             *t = std::move(defaultValue);
387             return true;
388         }
389         return conv(t, child, param);
390     }
391 
392     template <typename T>
parseOptionalChildandroid::vintf::XmlNodeConverter393     inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
394                                    std::optional<T>* t, const BuildObjectParam& param) const {
395         NodeType* child = getChild(root, conv.elementName());
396         if (child == nullptr) {
397             *t = std::nullopt;
398             return true;
399         }
400         *t = std::make_optional<T>();
401         return conv(&**t, child, param);
402     }
403 
404     template <typename T>
parseChildrenandroid::vintf::XmlNodeConverter405     inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v,
406                               const BuildObjectParam& param) const {
407         auto nodes = getChildren(root, conv.elementName());
408         v->resize(nodes.size());
409         for (size_t i = 0; i < nodes.size(); ++i) {
410             if (!conv(&v->at(i), nodes[i], param)) {
411                 *param.error = "Could not parse element with name <" + conv.elementName() +
412                                "> in element <" + this->elementName() + ">: " + *param.error;
413                 return false;
414             }
415         }
416         return true;
417     }
418 
419     template <typename Container, typename T = typename Container::value_type,
420               typename = typename Container::key_compare>
parseChildrenandroid::vintf::XmlNodeConverter421     inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, Container* s,
422                               const BuildObjectParam& param) const {
423         std::vector<T> vec;
424         if (!parseChildren(root, conv, &vec, param)) {
425             return false;
426         }
427         s->clear();
428         s->insert(vec.begin(), vec.end());
429         if (s->size() != vec.size()) {
430             *param.error = "Duplicated elements <" + conv.elementName() + "> in element <" +
431                            this->elementName() + ">";
432             s->clear();
433             return false;
434         }
435         return true;
436     }
437 
438     template <typename K, typename V>
parseChildrenandroid::vintf::XmlNodeConverter439     inline bool parseChildren(NodeType* root, const XmlNodeConverter<std::pair<K, V>>& conv,
440                               std::map<K, V>* s, const BuildObjectParam& param) const {
441         return parseChildren<std::map<K, V>, std::pair<K, V>>(root, conv, s, param);
442     }
443 
parseTextandroid::vintf::XmlNodeConverter444     inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const {
445         *s = getText(node);
446         return true;
447     }
448 
449     template <typename T>
parseTextandroid::vintf::XmlNodeConverter450     inline bool parseText(NodeType* node, T* s, std::string* error) const {
451         bool (*parser)(const std::string&, T*) = ::android::vintf::parse;
452         return parseText(node, s, {parser}, error);
453     }
454 
455     template <typename T>
parseTextandroid::vintf::XmlNodeConverter456     inline bool parseText(NodeType* node, T* s,
457                           const std::function<bool(const std::string&, T*)>& parse,
458                           std::string* error) const {
459         std::string text = getText(node);
460         bool ret = parse(text, s);
461         if (!ret) {
462             *error = "Could not parse text \"" + text + "\" in element <" + elementName() + ">";
463         }
464         return ret;
465     }
466 };
467 
468 template<typename Object>
469 struct XmlTextConverter : public XmlNodeConverter<Object> {
mutateNodeandroid::vintf::XmlTextConverter470     void mutateNode(const Object& object, NodeType* root,
471                     const MutateNodeParam& param) const override {
472         appendText(root, ::android::vintf::to_string(object), param.d);
473     }
buildObjectandroid::vintf::XmlTextConverter474     bool buildObject(Object* object, NodeType* root, const BuildObjectParam& param) const override {
475         return this->parseText(root, object, param.error);
476     }
477 };
478 
479 template <typename Pair, typename FirstConverter, typename SecondConverter>
480 struct XmlPairConverter : public XmlNodeConverter<Pair> {
mutateNodeandroid::vintf::XmlPairConverter481     void mutateNode(const Pair& object, NodeType* root,
482                     const MutateNodeParam& param) const override {
483         appendChild(root, FirstConverter{}(object.first, param));
484         appendChild(root, SecondConverter{}(object.second, param));
485     }
buildObjectandroid::vintf::XmlPairConverter486     bool buildObject(Pair* object, NodeType* root, const BuildObjectParam& param) const override {
487         return this->parseChild(root, FirstConverter{}, &object->first, param) &&
488                this->parseChild(root, SecondConverter{}, &object->second, param);
489     }
490 };
491 
492 // ---------------------- XmlNodeConverter definitions end
493 
494 struct VersionConverter : public XmlTextConverter<Version> {
elementNameandroid::vintf::VersionConverter495     std::string elementName() const override { return "version"; }
496 };
497 
498 struct SepolicyVersionConverter : public XmlTextConverter<SepolicyVersion> {
elementNameandroid::vintf::SepolicyVersionConverter499     std::string elementName() const override { return "version"; }
500 };
501 
502 struct VersionRangeConverter : public XmlTextConverter<VersionRange> {
elementNameandroid::vintf::VersionRangeConverter503     std::string elementName() const override { return "version"; }
504 };
505 
506 struct SepolicyVersionRangeConverter : public XmlTextConverter<SepolicyVersionRange> {
elementNameandroid::vintf::SepolicyVersionRangeConverter507     std::string elementName() const override { return "sepolicy-version"; }
508 };
509 
510 // <version>100</version> <=> Version{kFakeAidlMajorVersion, 100}
511 struct AidlVersionConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::AidlVersionConverter512     std::string elementName() const override { return "version"; }
mutateNodeandroid::vintf::AidlVersionConverter513     void mutateNode(const Version& object, NodeType* root,
514                     const MutateNodeParam& param) const override {
515         appendText(root, aidlVersionToString(object), param.d);
516     }
buildObjectandroid::vintf::AidlVersionConverter517     bool buildObject(Version* object, NodeType* root,
518                      const BuildObjectParam& param) const override {
519         return parseText(root, object, {parseAidlVersion}, param.error);
520     }
521 };
522 
523 // <version>100</version> <=> VersionRange{kFakeAidlMajorVersion, 100, 100}
524 // <version>100-105</version> <=> VersionRange{kFakeAidlMajorVersion, 100, 105}
525 struct AidlVersionRangeConverter : public XmlNodeConverter<VersionRange> {
elementNameandroid::vintf::AidlVersionRangeConverter526     std::string elementName() const override { return "version"; }
mutateNodeandroid::vintf::AidlVersionRangeConverter527     void mutateNode(const VersionRange& object, NodeType* root,
528                     const MutateNodeParam& param) const override {
529         appendText(root, aidlVersionRangeToString(object), param.d);
530     }
buildObjectandroid::vintf::AidlVersionRangeConverter531     bool buildObject(VersionRange* object, NodeType* root,
532                      const BuildObjectParam& param) const override {
533         return parseText(root, object, {parseAidlVersionRange}, param.error);
534     }
535 };
536 
537 struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
elementNameandroid::vintf::TransportArchConverter538     std::string elementName() const override { return "transport"; }
mutateNodeandroid::vintf::TransportArchConverter539     void mutateNode(const TransportArch& object, NodeType* root,
540                     const MutateNodeParam& param) const override {
541         if (object.arch != Arch::ARCH_EMPTY) {
542             appendAttr(root, "arch", object.arch);
543         }
544         if (object.ip.has_value()) {
545             appendAttr(root, "ip", *object.ip);
546         }
547         if (object.port.has_value()) {
548             appendAttr(root, "port", *object.port);
549         }
550         appendText(root, ::android::vintf::to_string(object.transport), param.d);
551     }
buildObjectandroid::vintf::TransportArchConverter552     bool buildObject(TransportArch* object, NodeType* root,
553                      const BuildObjectParam& param) const override {
554         if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, param) ||
555             !parseOptionalAttr(root, "ip", {}, &object->ip, param) ||
556             !parseOptionalAttr(root, "port", {}, &object->port, param) ||
557             !parseText(root, &object->transport, param.error)) {
558             return false;
559         }
560         if (!object->isValid(param.error)) {
561             return false;
562         }
563         return true;
564     }
565 };
566 
567 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
elementNameandroid::vintf::KernelConfigTypedValueConverter568     std::string elementName() const override { return "value"; }
mutateNodeandroid::vintf::KernelConfigTypedValueConverter569     void mutateNode(const KernelConfigTypedValue& object, NodeType* root,
570                     const MutateNodeParam& param) const override {
571         appendAttr(root, "type", object.mType);
572         appendText(root, ::android::vintf::to_string(object), param.d);
573     }
buildObjectandroid::vintf::KernelConfigTypedValueConverter574     bool buildObject(KernelConfigTypedValue* object, NodeType* root,
575                      const BuildObjectParam& param) const override {
576         std::string stringValue;
577         if (!parseAttr(root, "type", &object->mType, param.error) ||
578             !parseText(root, &stringValue, param.error)) {
579             return false;
580         }
581         if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
582             *param.error = "Could not parse kernel config value \"" + stringValue + "\"";
583             return false;
584         }
585         return true;
586     }
587 };
588 
589 struct KernelConfigKeyConverter : public XmlTextConverter<KernelConfigKey> {
elementNameandroid::vintf::KernelConfigKeyConverter590     std::string elementName() const override { return "key"; }
591 };
592 
593 struct MatrixKernelConfigConverter : public XmlPairConverter<KernelConfig, KernelConfigKeyConverter,
594                                                              KernelConfigTypedValueConverter> {
elementNameandroid::vintf::MatrixKernelConfigConverter595     std::string elementName() const override { return "config"; }
596 };
597 
598 struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
elementNameandroid::vintf::HalInterfaceConverter599     std::string elementName() const override { return "interface"; }
mutateNodeandroid::vintf::HalInterfaceConverter600     void mutateNode(const HalInterface& object, NodeType* root,
601                     const MutateNodeParam& param) const override {
602         if (!object.name().empty()) {
603             appendTextElement(root, "name", object.name(), param.d);
604         }
605         appendTextElements(root, "instance", object.mInstances, param.d);
606         appendTextElements(root, "regex-instance", object.mRegexes, param.d);
607     }
buildObjectandroid::vintf::HalInterfaceConverter608     bool buildObject(HalInterface* object, NodeType* root,
609                      const BuildObjectParam& param) const override {
610         std::vector<std::string> instances;
611         std::vector<std::string> regexes;
612         if (!parseOptionalTextElement(root, "name", {}, &object->mName, param.error) ||
613             !parseTextElements(root, "instance", &instances, param.error) ||
614             !parseTextElements(root, "regex-instance", &regexes, param.error)) {
615             return false;
616         }
617         bool success = true;
618         for (const auto& e : instances) {
619             if (!object->insertInstance(e, false /* isRegex */)) {
620                 if (!param.error->empty()) *param.error += "\n";
621                 *param.error += "Duplicated instance '" + e + "' in " + object->name();
622                 success = false;
623             }
624         }
625         for (const auto& e : regexes) {
626             details::Regex regex;
627             if (!regex.compile(e)) {
628                 if (!param.error->empty()) *param.error += "\n";
629                 *param.error += "Invalid regular expression '" + e + "' in " + object->name();
630                 success = false;
631             }
632             if (!object->insertInstance(e, true /* isRegex */)) {
633                 if (!param.error->empty()) *param.error += "\n";
634                 *param.error += "Duplicated regex-instance '" + e + "' in " + object->name();
635                 success = false;
636             }
637         }
638         return success;
639     }
640 };
641 
642 struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
elementNameandroid::vintf::MatrixHalConverter643     std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::MatrixHalConverter644     void mutateNode(const MatrixHal& object, NodeType* root,
645                     const MutateNodeParam& param) const override {
646         appendAttr(root, "format", object.format);
647         appendAttr(root, "optional", object.optional);
648         // Only include if it is not the default empty value
649         if (object.exclusiveTo != ExclusiveTo::EMPTY) {
650             appendAttr(root, "exclusive-to", object.exclusiveTo);
651         }
652         // Only include update-via-apex if enabled
653         if (object.updatableViaApex) {
654             appendAttr(root, "updatable-via-apex", object.updatableViaApex);
655         }
656         appendTextElement(root, "name", object.name, param.d);
657         if (object.format == HalFormat::AIDL) {
658             // By default, buildObject() assumes a <version>0</version> tag if no <version> tag
659             // is specified. Don't output any <version> tag if there's only one <version>0</version>
660             // tag.
661             if (object.versionRanges.size() != 1 ||
662                 object.versionRanges[0] != details::kDefaultAidlVersionRange) {
663                 appendChildren(root, AidlVersionRangeConverter{}, object.versionRanges, param);
664             }
665         } else {
666             appendChildren(root, VersionRangeConverter{}, object.versionRanges, param);
667         }
668         appendChildren(root, HalInterfaceConverter{}, iterateValues(object.interfaces), param);
669     }
buildObjectandroid::vintf::MatrixHalConverter670     bool buildObject(MatrixHal* object, NodeType* root,
671                      const BuildObjectParam& param) const override {
672         std::vector<HalInterface> interfaces;
673         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, param) ||
674             !parseOptionalAttr(root, "optional", true /* defaultValue */, &object->optional,
675                                param) ||
676             !parseOptionalAttr(root, "exclusive-to", ExclusiveTo::EMPTY, &object->exclusiveTo,
677                                param) ||
678             !parseOptionalAttr(root, "updatable-via-apex", false /* defaultValue */,
679                                &object->updatableViaApex, param) ||
680             !parseTextElement(root, "name", &object->name, param.error) ||
681             !parseChildren(root, HalInterfaceConverter{}, &interfaces, param)) {
682             return false;
683         }
684         if (object->format == HalFormat::AIDL) {
685             if (!parseChildren(root, AidlVersionRangeConverter{}, &object->versionRanges, param)) {
686                 return false;
687             }
688             // Insert fake version for AIDL HALs so that compatibility check for AIDL and other
689             // HAL formats can be unified.
690             if (object->versionRanges.empty()) {
691                 object->versionRanges.push_back(details::kDefaultAidlVersionRange);
692             }
693         } else {
694             if (!parseChildren(root, VersionRangeConverter{}, &object->versionRanges, param)) {
695                 return false;
696             }
697         }
698         for (auto&& interface : interfaces) {
699             std::string name{interface.name()};
700             auto res = object->interfaces.emplace(std::move(name), std::move(interface));
701             if (!res.second) {
702                 *param.error = "Duplicated interface entry \"" + res.first->first +
703                                "\"; if additional instances are needed, add them to the "
704                                "existing <interface> node.";
705                 return false;
706             }
707         }
708         if (!checkAdditionalRestrictionsOnHal(*object, param.error)) {
709             return false;
710         }
711 
712         if (!object->isValid(param.error)) {
713             param.error->insert(0, "'" + object->name + "' is not a valid Matrix HAL: ");
714             return false;
715         }
716         return true;
717     }
718 
719    private:
checkAdditionalRestrictionsOnHalandroid::vintf::MatrixHalConverter720     bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal, std::string* error) const {
721         // Do not check for target-side libvintf to avoid restricting ability for upgrade
722         // accidentally.
723         if constexpr (kDevice) {
724             return true;
725         }
726         if (hal.getName() == "netutils-wrapper") {
727             if (hal.versionRanges.size() != 1) {
728                 *error =
729                     "netutils-wrapper HAL must specify exactly one version x.0, "
730                     "but multiple <version> element is specified.";
731                 return false;
732             }
733             const VersionRange& v = hal.versionRanges.at(0);
734             if (!v.isSingleVersion()) {
735                 *error =
736                     "netutils-wrapper HAL must specify exactly one version x.0, "
737                     "but a range is provided. Perhaps you mean '" +
738                     to_string(Version{v.majorVer, 0}) + "'?";
739                 return false;
740             }
741             if (v.minMinor != 0) {
742                 *error =
743                     "netutils-wrapper HAL must specify exactly one version x.0, "
744                     "but minor version is not 0. Perhaps you mean '" +
745                     to_string(Version{v.majorVer, 0}) + "'?";
746                 return false;
747             }
748         }
749         return true;
750     }
751 };
752 
753 struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> {
elementNameandroid::vintf::MatrixKernelConditionsConverter754     std::string elementName() const override { return "conditions"; }
mutateNodeandroid::vintf::MatrixKernelConditionsConverter755     void mutateNode(const std::vector<KernelConfig>& object, NodeType* root,
756                     const MutateNodeParam& param) const override {
757         appendChildren(root, MatrixKernelConfigConverter{}, object, param);
758     }
buildObjectandroid::vintf::MatrixKernelConditionsConverter759     bool buildObject(std::vector<KernelConfig>* object, NodeType* root,
760                      const BuildObjectParam& param) const override {
761         return parseChildren(root, MatrixKernelConfigConverter{}, object, param);
762     }
763 };
764 
765 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
elementNameandroid::vintf::MatrixKernelConverter766     std::string elementName() const override { return "kernel"; }
mutateNodeandroid::vintf::MatrixKernelConverter767     void mutateNode(const MatrixKernel& object, NodeType* root,
768                     const MutateNodeParam& param) const override {
769         KernelVersion kv = object.mMinLts;
770         if (!param.flags.isKernelMinorRevisionEnabled()) {
771             kv.minorRev = 0u;
772         }
773         appendAttr(root, "version", kv);
774 
775         if (object.getSourceMatrixLevel() != Level::UNSPECIFIED) {
776             appendAttr(root, "level", object.getSourceMatrixLevel());
777         }
778 
779         if (!object.mConditions.empty()) {
780             appendChild(root, MatrixKernelConditionsConverter{}(object.mConditions, param));
781         }
782         if (param.flags.isKernelConfigsEnabled()) {
783             appendChildren(root, MatrixKernelConfigConverter{}, object.mConfigs, param);
784         }
785     }
buildObjectandroid::vintf::MatrixKernelConverter786     bool buildObject(MatrixKernel* object, NodeType* root,
787                      const BuildObjectParam& param) const override {
788         Level sourceMatrixLevel = Level::UNSPECIFIED;
789         if (!parseAttr(root, "version", &object->mMinLts, param.error) ||
790             !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &sourceMatrixLevel, param) ||
791             !parseOptionalChild(root, MatrixKernelConditionsConverter{}, {}, &object->mConditions,
792                                 param) ||
793             !parseChildren(root, MatrixKernelConfigConverter{}, &object->mConfigs, param)) {
794             return false;
795         }
796         object->setSourceMatrixLevel(sourceMatrixLevel);
797         return true;
798     }
799 };
800 
801 struct FqInstanceConverter : public XmlTextConverter<FqInstance> {
elementNameandroid::vintf::FqInstanceConverter802     std::string elementName() const override { return "fqname"; }
803 };
804 
805 // Convert ManifestHal from and to XML. Returned object is guaranteed to have
806 // .isValid() == true.
807 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
elementNameandroid::vintf::ManifestHalConverter808     std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::ManifestHalConverter809     void mutateNode(const ManifestHal& object, NodeType* root,
810                     const MutateNodeParam& param) const override {
811         appendAttr(root, "format", object.format);
812         // Only include if it is not the default empty value
813         if (object.exclusiveTo != ExclusiveTo::EMPTY) {
814             appendAttr(root, "exclusive-to", object.exclusiveTo);
815         }
816         appendTextElement(root, "name", object.name, param.d);
817         if (!object.transportArch.empty()) {
818             appendChild(root, TransportArchConverter{}(object.transportArch, param));
819         }
820         if (object.format == HalFormat::AIDL) {
821             // By default, buildObject() assumes a <version>0</version> tag if no <version> tag
822             // is specified. Don't output any <version> tag if there's only one <version>0</version>
823             // tag.
824             if (object.versions.size() != 1 || object.versions[0] != details::kDefaultAidlVersion) {
825                 appendChildren(root, AidlVersionConverter{}, object.versions, param);
826             }
827         } else {
828             appendChildren(root, VersionConverter{}, object.versions, param);
829         }
830         if (object.isOverride()) {
831             appendAttr(root, "override", object.isOverride());
832         }
833         if (const auto& apex = object.updatableViaApex(); apex.has_value()) {
834             appendAttr(root, "updatable-via-apex", apex.value());
835         }
836         // Only include update-via-system if enabled
837         if (object.updatableViaSystem()) {
838             appendAttr(root, "updatable-via-system", object.updatableViaSystem());
839         }
840         if (const auto& accessor = object.accessor(); accessor.has_value()) {
841             appendTextElement(root, "accessor", accessor.value(), param.d);
842         }
843         if (param.flags.isFqnameEnabled()) {
844             std::set<std::string> simpleFqInstances;
845             object.forEachInstance([&simpleFqInstances](const auto& manifestInstance) {
846                 simpleFqInstances.emplace(manifestInstance.getSimpleFqInstance());
847                 return true;
848             });
849             appendTextElements(root, FqInstanceConverter{}.elementName(), simpleFqInstances,
850                                param.d);
851         }
852         if (object.getMaxLevel() != Level::UNSPECIFIED) {
853             appendAttr(root, "max-level", object.getMaxLevel());
854         }
855         if (object.getMinLevel() != Level::UNSPECIFIED) {
856             appendAttr(root, "min-level", object.getMinLevel());
857         }
858     }
buildObjectandroid::vintf::ManifestHalConverter859     bool buildObject(ManifestHal* object, NodeType* root,
860                      const BuildObjectParam& param) const override {
861         std::vector<HalInterface> interfaces;
862         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, param) ||
863             !parseOptionalAttr(root, "override", false, &object->mIsOverride, param) ||
864             !parseOptionalAttr(root, "exclusive-to", ExclusiveTo::EMPTY, &object->exclusiveTo,
865                                param) ||
866             !parseOptionalAttr(root, "updatable-via-apex", {}, &object->mUpdatableViaApex, param) ||
867             !parseOptionalAttr(root, "updatable-via-system", false /* defaultValue */,
868                                &object->mUpdatableViaSystem, param) ||
869             !parseOptionalTextElement(root, "accessor", {}, &object->mAccessor, param.error) ||
870             !parseTextElement(root, "name", &object->name, param.error) ||
871             !parseOptionalChild(root, TransportArchConverter{}, {}, &object->transportArch,
872                                 param) ||
873             !parseOptionalAttr(root, "max-level", Level::UNSPECIFIED, &object->mMaxLevel, param) ||
874             !parseOptionalAttr(root, "min-level", Level::UNSPECIFIED, &object->mMinLevel, param)) {
875             return false;
876         }
877         if (getChildren(root, "accessor").size() > 1) {
878             *param.error = "No more than one <accessor> is allowed in <hal>";
879             return false;
880         }
881 
882         std::string_view apexName = parseApexName(param.fileName);
883         if (!apexName.empty()) {
884             if (object->mUpdatableViaApex.has_value()) {
885                 // When defined in APEX, updatable-via-apex can be either
886                 // - ""(empty)  : the HAL isn't updatable even if it's in APEX
887                 // - {apex name}: the HAL is updtable via the current APEX
888                 const std::string& updatableViaApex = object->mUpdatableViaApex.value();
889                 if (!updatableViaApex.empty() && apexName.compare(updatableViaApex) != 0) {
890                     *param.error = "Invalid APEX HAL " + object->name + ": updatable-via-apex " +
891                                    updatableViaApex + " doesn't match with the defining APEX " +
892                                    std::string(apexName) + "\n";
893                     return false;
894                 }
895             } else {
896                 // Set updatable-via-apex to the defining APEX when it's not set explicitly.
897                 // This should be set before calling insertInstances() which copies the current
898                 // value to ManifestInstance.
899                 object->mUpdatableViaApex = apexName;
900             }
901         }
902 
903         switch (object->format) {
904             case HalFormat::HIDL: {
905                 if (!parseChildren(root, VersionConverter{}, &object->versions, param))
906                     return false;
907                 if (object->transportArch.empty()) {
908                     *param.error =
909                         "HIDL HAL '" + object->name + "' should have <transport> defined.";
910                     return false;
911                 }
912                 if (object->transportArch.transport == Transport::INET ||
913                     object->transportArch.ip.has_value() ||
914                     object->transportArch.port.has_value()) {
915                     *param.error = "HIDL HAL '" + object->name +
916                                    "' should not have <transport> \"inet\" " +
917                                    "or ip or port attributes defined.";
918                     return false;
919                 }
920             } break;
921             case HalFormat::NATIVE: {
922                 if (!parseChildren(root, VersionConverter{}, &object->versions, param))
923                     return false;
924                 if (!object->transportArch.empty()) {
925                     *param.error =
926                         "Native HAL '" + object->name + "' should not have <transport> defined.";
927                     return false;
928                 }
929             } break;
930             case HalFormat::AIDL: {
931                 if (!object->transportArch.empty() &&
932                     object->transportArch.transport != Transport::INET) {
933                     if (param.metaVersion >= kMetaVersionAidlInet) {
934                         *param.error = "AIDL HAL '" + object->name +
935                                        R"(' only supports "inet" or empty <transport>, found ")" +
936                                        to_string(object->transportArch) + "\"";
937                         return false;
938                     }
939                     LOG(WARNING) << "Ignoring <transport> on manifest <hal format=\"aidl\"> "
940                                  << object->name << ". Only \"inet\" supported.";
941                     object->transportArch = {};
942                 }
943                 if (!parseChildren(root, AidlVersionConverter{}, &object->versions, param)) {
944                     return false;
945                 }
946                 // Insert fake version for AIDL HALs so that forEachInstance works.
947                 if (object->versions.empty()) {
948                     object->versions.push_back(details::kDefaultAidlVersion);
949                 }
950             } break;
951             default: {
952                 LOG(FATAL) << "Unhandled HalFormat "
953                            << static_cast<typename std::underlying_type<HalFormat>::type>(
954                                   object->format);
955             } break;
956         }
957         if (!object->transportArch.isValid(param.error)) return false;
958 
959         // Parse <fqname> into fqInstances list
960         std::set<FqInstance> fqInstances;
961         if (!parseChildren(root, FqInstanceConverter{}, &fqInstances, param)) {
962             return false;
963         }
964 
965         // Handle deprecated <interface> x <instance>
966         if (!parseChildren(root, HalInterfaceConverter{}, &interfaces, param)) {
967             return false;
968         }
969         // Check duplicated <interface><name>
970         std::set<std::string> interface_names;
971         for (auto &&interface : interfaces) {
972             auto res = interface_names.emplace(interface.name());
973             if (!res.second) {
974                 *param.error = "Duplicated interface entry \"" + *res.first +
975                                "\"; if additional instances are needed, add them to the "
976                                "existing <interface> node.";
977                 return false;
978             }
979         }
980         // Turn <version> x <interface> x <instance> into <fqname>s; insert into
981         // fqInstances list.
982         bool convertedInstancesIntoFqnames = false;
983         for (const auto& v : object->versions) {
984             for (const auto& intf : interfaces) {
985                 if (param.metaVersion >= kMetaVersionNoHalInterfaceInstance &&
986                     (object->format == HalFormat::HIDL || object->format == HalFormat::AIDL) &&
987                     !intf.hasAnyInstance()) {
988                     *param.error +=
989                         "<hal> " + object->name + " <interface> " + intf.name() +
990                         " has no <instance>. Either specify <instance> or, "
991                         "preferably, specify <fqname> and delete <version> and <interface>.";
992                     return false;
993                 }
994                 bool cont = intf.forEachInstance(
995                     [&v, &fqInstances, &convertedInstancesIntoFqnames, &object, &param](
996                         const auto& interface, const auto& instance, bool /* isRegex */) {
997                         auto fqInstance = details::convertLegacyInstanceIntoFqInstance(
998                             object->name, v, interface, instance, object->format, param.error);
999 
1000                         if (!fqInstance.has_value()) {
1001                             return false;
1002                         }
1003 
1004                         // Check for duplication in fqInstances.
1005                         // Before kMetaVersionNoHalInterfaceInstance: It is okay to have duplication
1006                         // between <interface> and <fqname>.
1007                         // After kMetaVersionNoHalInterfaceInstance: Duplication between
1008                         // <interface> and <fqname> is not allowed.
1009                         auto&& [it, inserted] = fqInstances.emplace(std::move(fqInstance.value()));
1010                         if (param.metaVersion >= kMetaVersionNoHalInterfaceInstance && !inserted) {
1011                             std::string debugString =
1012                                 object->format == HalFormat::AIDL
1013                                     ? toAidlFqnameString(object->name, interface, instance)
1014                                     : toFQNameString(object->name, v, interface, instance);
1015                             *param.error = "Duplicated " + debugString +
1016                                            " in <interface><instance> and <fqname>. ";
1017                             if constexpr (kDevice) {
1018                                 *param.error +=
1019                                     "(Did you copy source manifests to the device directly "
1020                                     "without going through assemble_vintf, e.g. not using "
1021                                     "DEVICE_MANIFEST_FILE or ODM_MANIFEST_FILES?)";
1022                             } else {
1023                                 *param.error += "Remove deprecated <interface>.";
1024                             }
1025                             return false;
1026                         }
1027 
1028                         convertedInstancesIntoFqnames = true;
1029                         return true;  // continue
1030                     });
1031                 if (!cont) {
1032                     return false;
1033                 }
1034             }
1035         }
1036 
1037         if (!checkAdditionalRestrictionsOnHal(*object, param.error)) {
1038             return false;
1039         }
1040 
1041         // For HIDL, if any <version> x <interface> x <instance> tuple, all <version>
1042         // tags can be cleared. <version> information is already in <fqname>'s.
1043         // For AIDL, <version> information is not in <fqname>, so don't clear them.
1044         // For HALs with only <version> but no <interface>
1045         // (e.g. native HALs like netutils-wrapper), <version> is kept.
1046         if (convertedInstancesIntoFqnames && object->format != HalFormat::AIDL) {
1047             object->versions.clear();
1048         }
1049 
1050         std::set<FqInstance> fqInstancesToInsert;
1051         for (auto& e : fqInstances) {
1052             if (e.hasPackage()) {
1053                 *param.error = "Should not specify package: \"" + e.string() + "\"";
1054                 return false;
1055             }
1056             if (object->format == HalFormat::AIDL) {
1057                 // <fqname> in AIDL HALs should not contain version.
1058                 if (e.hasVersion()) {
1059                     *param.error = "Should not specify version in <fqname> for AIDL HAL: \"" +
1060                                    e.string() + "\"";
1061                     return false;
1062                 }
1063                 // Put in the fake kDefaultAidlVersion so that HalManifest can
1064                 // store it in an FqInstance object with a non-empty package.
1065                 FqInstance withFakeVersion;
1066                 if (!withFakeVersion.setTo(details::kDefaultAidlVersion.majorVer,
1067                                            details::kDefaultAidlVersion.minorVer, e.getInterface(),
1068                                            e.getInstance())) {
1069                     return false;
1070                 }
1071                 fqInstancesToInsert.emplace(std::move(withFakeVersion));
1072             } else {
1073                 fqInstancesToInsert.emplace(std::move(e));
1074             }
1075         }
1076 
1077         if (param.metaVersion >= kMetaVersionNoHalInterfaceInstance &&
1078             (object->format == HalFormat::HIDL || object->format == HalFormat::AIDL) &&
1079             fqInstancesToInsert.empty() && !object->isOverride()) {
1080             *param.error = "<hal> " + object->name + " has no instance. Fix by adding <fqname>.";
1081             return false;
1082         }
1083 
1084         bool allowMajorVersionDup = param.metaVersion < kMetaVersionNoHalInterfaceInstance;
1085         if (!object->insertInstances(fqInstancesToInsert, allowMajorVersionDup, param.error)) {
1086             return false;
1087         }
1088 
1089         if (!object->isValid(param.error)) {
1090             param.error->insert(0, "'" + object->name + "' is not a valid Manifest HAL: ");
1091             return false;
1092         }
1093 
1094         return true;
1095     }
1096 
1097    private:
checkAdditionalRestrictionsOnHalandroid::vintf::ManifestHalConverter1098     bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal, std::string* error) const {
1099         // Do not check for target-side libvintf to avoid restricting upgrade accidentally.
1100         if constexpr (kDevice) {
1101             return true;
1102         }
1103         if (hal.getName() == "netutils-wrapper") {
1104             for (const Version& v : hal.versions) {
1105                 if (v.minorVer != 0) {
1106                     *error =
1107                         "netutils-wrapper HAL must specify exactly one version x.0, "
1108                         "but minor version is not 0. Perhaps you mean '" +
1109                         to_string(Version{v.majorVer, 0}) + "'?";
1110                     return false;
1111                 }
1112             }
1113         }
1114         return true;
1115     }
1116 };
1117 
1118 struct KernelSepolicyVersionConverter : public XmlTextConverter<KernelSepolicyVersion> {
elementNameandroid::vintf::KernelSepolicyVersionConverter1119     std::string elementName() const override { return "kernel-sepolicy-version"; }
1120 };
1121 
1122 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
elementNameandroid::vintf::SepolicyConverter1123     std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::SepolicyConverter1124     void mutateNode(const Sepolicy& object, NodeType* root,
1125                     const MutateNodeParam& param) const override {
1126         appendChild(root, KernelSepolicyVersionConverter{}(object.kernelSepolicyVersion(), param));
1127         appendChildren(root, SepolicyVersionRangeConverter{}, object.sepolicyVersions(), param);
1128     }
buildObjectandroid::vintf::SepolicyConverter1129     bool buildObject(Sepolicy* object, NodeType* root,
1130                      const BuildObjectParam& param) const override {
1131         if (!parseChild(root, KernelSepolicyVersionConverter{}, &object->mKernelSepolicyVersion,
1132                         param) ||
1133             !parseChildren(root, SepolicyVersionRangeConverter{}, &object->mSepolicyVersionRanges,
1134                            param)) {
1135             return false;
1136         }
1137         return true;
1138     }
1139 };
1140 
1141 struct [[deprecated]] VndkVersionRangeConverter : public XmlTextConverter<VndkVersionRange> {
elementNameandroid::vintf::VndkVersionRangeConverter1142     std::string elementName() const override { return "version"; }
1143 };
1144 
1145 struct VndkVersionConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::VndkVersionConverter1146     std::string elementName() const override { return "version"; }
1147 };
1148 
1149 struct VndkLibraryConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::VndkLibraryConverter1150     std::string elementName() const override { return "library"; }
1151 };
1152 
1153 struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> {
elementNameandroid::vintf::VndkConverter1154     std::string elementName() const override { return "vndk"; }
mutateNodeandroid::vintf::VndkConverter1155     void mutateNode(const Vndk& object, NodeType* root,
1156                     const MutateNodeParam& param) const override {
1157         appendChild(root, VndkVersionRangeConverter{}(object.mVersionRange, param));
1158         appendChildren(root, VndkLibraryConverter{}, object.mLibraries, param);
1159     }
buildObjectandroid::vintf::VndkConverter1160     bool buildObject(Vndk* object, NodeType* root, const BuildObjectParam& param) const override {
1161         if (!parseChild(root, VndkVersionRangeConverter{}, &object->mVersionRange, param) ||
1162             !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, param)) {
1163             return false;
1164         }
1165         return true;
1166     }
1167 };
1168 
1169 struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> {
elementNameandroid::vintf::VendorNdkConverter1170     std::string elementName() const override { return "vendor-ndk"; }
mutateNodeandroid::vintf::VendorNdkConverter1171     void mutateNode(const VendorNdk& object, NodeType* root,
1172                     const MutateNodeParam& param) const override {
1173         appendChild(root, VndkVersionConverter{}(object.mVersion, param));
1174         appendChildren(root, VndkLibraryConverter{}, object.mLibraries, param);
1175     }
buildObjectandroid::vintf::VendorNdkConverter1176     bool buildObject(VendorNdk* object, NodeType* root,
1177                      const BuildObjectParam& param) const override {
1178         if (!parseChild(root, VndkVersionConverter{}, &object->mVersion, param) ||
1179             !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, param)) {
1180             return false;
1181         }
1182         return true;
1183     }
1184 };
1185 
1186 struct SystemSdkVersionConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::SystemSdkVersionConverter1187     std::string elementName() const override { return "version"; }
1188 };
1189 
1190 struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> {
elementNameandroid::vintf::SystemSdkConverter1191     std::string elementName() const override { return "system-sdk"; }
mutateNodeandroid::vintf::SystemSdkConverter1192     void mutateNode(const SystemSdk& object, NodeType* root,
1193                     const MutateNodeParam& param) const override {
1194         appendChildren(root, SystemSdkVersionConverter{}, object.versions(), param);
1195     }
buildObjectandroid::vintf::SystemSdkConverter1196     bool buildObject(SystemSdk* object, NodeType* root,
1197                      const BuildObjectParam& param) const override {
1198         return parseChildren(root, SystemSdkVersionConverter{}, &object->mVersions, param);
1199     }
1200 };
1201 
1202 struct HalManifestSepolicyConverter : public XmlNodeConverter<SepolicyVersion> {
elementNameandroid::vintf::HalManifestSepolicyConverter1203     std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::HalManifestSepolicyConverter1204     void mutateNode(const SepolicyVersion& object, NodeType* root,
1205                     const MutateNodeParam& param) const override {
1206         appendChild(root, SepolicyVersionConverter{}(object, param));
1207     }
buildObjectandroid::vintf::HalManifestSepolicyConverter1208     bool buildObject(SepolicyVersion* object, NodeType* root,
1209                      const BuildObjectParam& param) const override {
1210         return parseChild(root, SepolicyVersionConverter{}, object, param);
1211     }
1212 };
1213 
1214 struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> {
elementNameandroid::vintf::ManifestXmlFileConverter1215     std::string elementName() const override { return "xmlfile"; }
mutateNodeandroid::vintf::ManifestXmlFileConverter1216     void mutateNode(const ManifestXmlFile& object, NodeType* root,
1217                     const MutateNodeParam& param) const override {
1218         appendTextElement(root, "name", object.name(), param.d);
1219         appendChild(root, VersionConverter{}(object.version(), param));
1220         if (!object.overriddenPath().empty()) {
1221             appendTextElement(root, "path", object.overriddenPath(), param.d);
1222         }
1223     }
buildObjectandroid::vintf::ManifestXmlFileConverter1224     bool buildObject(ManifestXmlFile* object, NodeType* root,
1225                      const BuildObjectParam& param) const override {
1226         if (!parseTextElement(root, "name", &object->mName, param.error) ||
1227             !parseChild(root, VersionConverter{}, &object->mVersion, param) ||
1228             !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, param.error)) {
1229             return false;
1230         }
1231         return true;
1232     }
1233 };
1234 
1235 struct StringKernelConfigKeyConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::StringKernelConfigKeyConverter1236     std::string elementName() const override { return "key"; }
1237 };
1238 
1239 struct KernelConfigValueConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::KernelConfigValueConverter1240     std::string elementName() const override { return "value"; }
1241 };
1242 
1243 struct StringKernelConfigConverter
1244     : public XmlPairConverter<std::pair<std::string, std::string>, StringKernelConfigKeyConverter,
1245                               KernelConfigValueConverter> {
elementNameandroid::vintf::StringKernelConfigConverter1246     std::string elementName() const override { return "config"; }
1247 };
1248 
1249 struct KernelInfoConverter : public XmlNodeConverter<KernelInfo> {
elementNameandroid::vintf::KernelInfoConverter1250     std::string elementName() const override { return "kernel"; }
mutateNodeandroid::vintf::KernelInfoConverter1251     void mutateNode(const KernelInfo& object, NodeType* root,
1252                     const MutateNodeParam& param) const override {
1253         if (object.version() != KernelVersion{}) {
1254             appendAttr(root, "version", object.version());
1255         }
1256         if (object.level() != Level::UNSPECIFIED) {
1257             appendAttr(root, "target-level", object.level());
1258         }
1259         if (param.flags.isKernelConfigsEnabled()) {
1260             appendChildren(root, StringKernelConfigConverter{}, object.configs(), param);
1261         }
1262     }
buildObjectandroid::vintf::KernelInfoConverter1263     bool buildObject(KernelInfo* object, NodeType* root,
1264                      const BuildObjectParam& param) const override {
1265         return parseOptionalAttr(root, "version", {}, &object->mVersion, param) &&
1266                parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
1267                                  param) &&
1268                parseChildren(root, StringKernelConfigConverter{}, &object->mConfigs, param);
1269     }
1270 };
1271 
1272 struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
elementNameandroid::vintf::HalManifestConverter1273     std::string elementName() const override { return "manifest"; }
mutateNodeandroid::vintf::HalManifestConverter1274     void mutateNode(const HalManifest& object, NodeType* root,
1275                     const MutateNodeParam& param) const override {
1276         if (param.flags.isMetaVersionEnabled()) {
1277             // Append the current metaversion of libvintf because the XML file
1278             // is generated with libvintf @ current meta version.
1279             appendAttr(root, "version", kMetaVersion);
1280         }
1281         if (param.flags.isSchemaTypeEnabled()) {
1282             appendAttr(root, "type", object.mType);
1283         }
1284 
1285         if (param.flags.isHalsEnabled()) {
1286             appendChildren(root, ManifestHalConverter{}, object.getHals(), param);
1287         }
1288         if (object.mType == SchemaType::DEVICE) {
1289             if (param.flags.isSepolicyEnabled()) {
1290                 if (object.device.mSepolicyVersion != SepolicyVersion{}) {
1291                     appendChild(root, HalManifestSepolicyConverter{}(object.device.mSepolicyVersion,
1292                                                                      param));
1293                 }
1294             }
1295             if (object.mLevel != Level::UNSPECIFIED) {
1296                 this->appendAttr(root, "target-level", object.mLevel);
1297             }
1298 
1299             if (param.flags.isKernelEnabled()) {
1300                 if (!!object.kernel()) {
1301                     appendChild(root, KernelInfoConverter{}(*object.kernel(), param));
1302                 }
1303             }
1304         } else if (object.mType == SchemaType::FRAMEWORK) {
1305             if (param.flags.isVndkEnabled()) {
1306 #pragma clang diagnostic push
1307 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1308                 appendChildren(root, VndkConverter{}, object.framework.mVndks, param);
1309 #pragma clang diagnostic pop
1310 
1311                 appendChildren(root, VendorNdkConverter{}, object.framework.mVendorNdks, param);
1312             }
1313             if (param.flags.isSsdkEnabled()) {
1314                 if (!object.framework.mSystemSdk.empty()) {
1315                     appendChild(root, SystemSdkConverter{}(object.framework.mSystemSdk, param));
1316                 }
1317             }
1318         }
1319 
1320         if (param.flags.isXmlFilesEnabled()) {
1321             appendChildren(root, ManifestXmlFileConverter{}, object.getXmlFiles(), param);
1322         }
1323     }
buildObjectandroid::vintf::HalManifestConverter1324     bool buildObject(HalManifest* object, NodeType* root,
1325                      const BuildObjectParam& constParam) const override {
1326         BuildObjectParam param = constParam;
1327         if (!parseAttr(root, "version", &param.metaVersion, param.error)) return false;
1328         if (param.metaVersion > kMetaVersion) {
1329             *param.error = "Unrecognized manifest.version " + to_string(param.metaVersion) +
1330                            " (libvintf@" + to_string(kMetaVersion) + ")";
1331             return false;
1332         }
1333         object->mSourceMetaVersion = param.metaVersion;
1334 
1335         if (!parseAttr(root, "type", &object->mType, param.error)) {
1336             return false;
1337         }
1338 
1339         std::vector<ManifestHal> hals;
1340         if (!parseChildren(root, ManifestHalConverter{}, &hals, param)) {
1341             return false;
1342         }
1343         for (auto&& hal : hals) {
1344             hal.setFileName(object->fileName());
1345         }
1346 
1347         if (object->mType == SchemaType::DEVICE) {
1348             // tags for device hal manifest only.
1349             // <sepolicy> can be missing because it can be determined at build time, not hard-coded
1350             // in the XML file.
1351             if (!parseOptionalChild(root, HalManifestSepolicyConverter{}, {},
1352                                     &object->device.mSepolicyVersion, param)) {
1353                 return false;
1354             }
1355 
1356             if (!parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
1357                                    param)) {
1358                 return false;
1359             }
1360 
1361             if (!parseOptionalChild(root, KernelInfoConverter{}, &object->device.mKernel, param)) {
1362                 return false;
1363             }
1364         } else if (object->mType == SchemaType::FRAMEWORK) {
1365 #pragma clang diagnostic push
1366 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1367             if (!parseChildren(root, VndkConverter{}, &object->framework.mVndks, param)) {
1368                 return false;
1369             }
1370             for (const auto& vndk : object->framework.mVndks) {
1371                 if (!vndk.mVersionRange.isSingleVersion()) {
1372                     *param.error = "vndk.version " + to_string(vndk.mVersionRange) +
1373                                    " cannot be a range for manifests";
1374                     return false;
1375                 }
1376             }
1377 #pragma clang diagnostic pop
1378 
1379             if (!parseChildren(root, VendorNdkConverter{}, &object->framework.mVendorNdks, param)) {
1380                 return false;
1381             }
1382 
1383             std::set<std::string> vendorNdkVersions;
1384             for (const auto& vendorNdk : object->framework.mVendorNdks) {
1385                 if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) {
1386                     *param.error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version();
1387                     return false;
1388                 }
1389                 vendorNdkVersions.insert(vendorNdk.version());
1390             }
1391 
1392             if (!parseOptionalChild(root, SystemSdkConverter{}, {}, &object->framework.mSystemSdk,
1393                                     param)) {
1394                 return false;
1395             }
1396         }
1397         for (auto &&hal : hals) {
1398             std::string description{hal.name};
1399             if (!object->add(std::move(hal), param.error)) {
1400                 param.error->insert(0, "Duplicated manifest.hal entry " + description + ": ");
1401                 return false;
1402             }
1403         }
1404 
1405         std::vector<ManifestXmlFile> xmlFiles;
1406         if (!parseChildren(root, ManifestXmlFileConverter{}, &xmlFiles, param)) {
1407             return false;
1408         }
1409         for (auto&& xmlFile : xmlFiles) {
1410             std::string description{xmlFile.name()};
1411             if (!object->addXmlFile(std::move(xmlFile))) {
1412                 *param.error = "Duplicated manifest.xmlfile entry " + description +
1413                                "; entries cannot have duplicated name and version";
1414                 return false;
1415             }
1416         }
1417 
1418         return true;
1419     }
1420 };
1421 
1422 struct AvbVersionConverter : public XmlTextConverter<Version> {
elementNameandroid::vintf::AvbVersionConverter1423     std::string elementName() const override { return "vbmeta-version"; }
1424 };
1425 
1426 struct AvbConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::AvbConverter1427     std::string elementName() const override { return "avb"; }
mutateNodeandroid::vintf::AvbConverter1428     void mutateNode(const Version& object, NodeType* root,
1429                     const MutateNodeParam& param) const override {
1430         appendChild(root, AvbVersionConverter{}(object, param));
1431     }
buildObjectandroid::vintf::AvbConverter1432     bool buildObject(Version* object, NodeType* root,
1433                      const BuildObjectParam& param) const override {
1434         return parseChild(root, AvbVersionConverter{}, object, param);
1435     }
1436 };
1437 
1438 struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> {
elementNameandroid::vintf::MatrixXmlFileConverter1439     std::string elementName() const override { return "xmlfile"; }
mutateNodeandroid::vintf::MatrixXmlFileConverter1440     void mutateNode(const MatrixXmlFile& object, NodeType* root,
1441                     const MutateNodeParam& param) const override {
1442         appendTextElement(root, "name", object.name(), param.d);
1443         appendAttr(root, "format", object.format());
1444         appendAttr(root, "optional", object.optional());
1445         appendChild(root, VersionRangeConverter{}(object.versionRange(), param));
1446         if (!object.overriddenPath().empty()) {
1447             appendTextElement(root, "path", object.overriddenPath(), param.d);
1448         }
1449     }
buildObjectandroid::vintf::MatrixXmlFileConverter1450     bool buildObject(MatrixXmlFile* object, NodeType* root,
1451                      const BuildObjectParam& param) const override {
1452         if (!parseTextElement(root, "name", &object->mName, param.error) ||
1453             !parseAttr(root, "format", &object->mFormat, param.error) ||
1454             !parseOptionalAttr(root, "optional", false, &object->mOptional, param) ||
1455             !parseChild(root, VersionRangeConverter{}, &object->mVersionRange, param) ||
1456             !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, param.error)) {
1457             return false;
1458         }
1459         return true;
1460     }
1461 };
1462 
1463 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
elementNameandroid::vintf::CompatibilityMatrixConverter1464     std::string elementName() const override { return "compatibility-matrix"; }
mutateNodeandroid::vintf::CompatibilityMatrixConverter1465     void mutateNode(const CompatibilityMatrix& object, NodeType* root,
1466                     const MutateNodeParam& param) const override {
1467         if (param.flags.isMetaVersionEnabled()) {
1468             appendAttr(root, "version", kMetaVersion);
1469         }
1470         if (param.flags.isSchemaTypeEnabled()) {
1471             appendAttr(root, "type", object.mType);
1472         }
1473 
1474         if (param.flags.isHalsEnabled()) {
1475             appendChildren(root, MatrixHalConverter{}, iterateValues(object.mHals), param);
1476         }
1477         if (object.mType == SchemaType::FRAMEWORK) {
1478             if (param.flags.isKernelEnabled()) {
1479                 appendChildren(root, MatrixKernelConverter{}, object.framework.mKernels, param);
1480             }
1481             if (param.flags.isSepolicyEnabled()) {
1482                 if (!(object.framework.mSepolicy == Sepolicy{})) {
1483                     appendChild(root, SepolicyConverter{}(object.framework.mSepolicy, param));
1484                 }
1485             }
1486             if (param.flags.isAvbEnabled()) {
1487                 if (!(object.framework.mAvbMetaVersion == Version{})) {
1488                     appendChild(root, AvbConverter{}(object.framework.mAvbMetaVersion, param));
1489                 }
1490             }
1491             if (object.mLevel != Level::UNSPECIFIED) {
1492                 this->appendAttr(root, "level", object.mLevel);
1493             }
1494         } else if (object.mType == SchemaType::DEVICE) {
1495             if (param.flags.isVndkEnabled()) {
1496 #pragma clang diagnostic push
1497 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1498                 if (!(object.device.mVndk == Vndk{})) {
1499                     appendChild(root, VndkConverter{}(object.device.mVndk, param));
1500                 }
1501 #pragma clang diagnostic pop
1502 
1503                 if (!(object.device.mVendorNdk == VendorNdk{})) {
1504                     appendChild(root, VendorNdkConverter{}(object.device.mVendorNdk, param));
1505                 }
1506             }
1507 
1508             if (param.flags.isSsdkEnabled()) {
1509                 if (!object.device.mSystemSdk.empty()) {
1510                     appendChild(root, SystemSdkConverter{}(object.device.mSystemSdk, param));
1511                 }
1512             }
1513         }
1514 
1515         if (param.flags.isXmlFilesEnabled()) {
1516             appendChildren(root, MatrixXmlFileConverter{}, object.getXmlFiles(), param);
1517         }
1518     }
buildObjectandroid::vintf::CompatibilityMatrixConverter1519     bool buildObject(CompatibilityMatrix* object, NodeType* root,
1520                      const BuildObjectParam& constParam) const override {
1521         BuildObjectParam param = constParam;
1522         if (!parseAttr(root, "version", &param.metaVersion, param.error)) return false;
1523         if (param.metaVersion > kMetaVersion) {
1524             *param.error = "Unrecognized compatibility-matrix.version " +
1525                            to_string(param.metaVersion) + " (libvintf@" + to_string(kMetaVersion) +
1526                            ")";
1527             return false;
1528         }
1529 
1530         std::vector<MatrixHal> hals;
1531         if (!parseAttr(root, "type", &object->mType, param.error) ||
1532             !parseChildren(root, MatrixHalConverter{}, &hals, param)) {
1533             return false;
1534         }
1535 
1536         if (object->mType == SchemaType::FRAMEWORK) {
1537             // <avb> and <sepolicy> can be missing because it can be determined at build time, not
1538             // hard-coded in the XML file.
1539             if (!parseChildren(root, MatrixKernelConverter{}, &object->framework.mKernels, param) ||
1540                 !parseOptionalChild(root, SepolicyConverter{}, {}, &object->framework.mSepolicy,
1541                                     param) ||
1542                 !parseOptionalChild(root, AvbConverter{}, {}, &object->framework.mAvbMetaVersion,
1543                                     param)) {
1544                 return false;
1545             }
1546 
1547             std::set<Version> seenKernelVersions;
1548             for (const auto& kernel : object->framework.mKernels) {
1549                 Version minLts(kernel.minLts().version, kernel.minLts().majorRev);
1550                 if (seenKernelVersions.find(minLts) != seenKernelVersions.end()) {
1551                     continue;
1552                 }
1553                 if (!kernel.conditions().empty()) {
1554                     *param.error = "First <kernel> for version " + to_string(minLts) +
1555                                    " must have empty <conditions> for backwards compatibility.";
1556                     return false;
1557                 }
1558                 seenKernelVersions.insert(minLts);
1559             }
1560 
1561             if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel, param)) {
1562                 return false;
1563             }
1564 
1565         } else if (object->mType == SchemaType::DEVICE) {
1566             // <vndk> can be missing because it can be determined at build time, not hard-coded
1567             // in the XML file.
1568 #pragma clang diagnostic push
1569 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1570             if (!parseOptionalChild(root, VndkConverter{}, {}, &object->device.mVndk, param)) {
1571                 return false;
1572             }
1573 #pragma clang diagnostic pop
1574 
1575             if (!parseOptionalChild(root, VendorNdkConverter{}, {}, &object->device.mVendorNdk,
1576                                     param)) {
1577                 return false;
1578             }
1579 
1580             if (!parseOptionalChild(root, SystemSdkConverter{}, {}, &object->device.mSystemSdk,
1581                                     param)) {
1582                 return false;
1583             }
1584         }
1585 
1586         for (auto &&hal : hals) {
1587             if (!object->add(std::move(hal))) {
1588                 *param.error = "Duplicated compatibility-matrix.hal entry";
1589                 return false;
1590             }
1591         }
1592 
1593         std::vector<MatrixXmlFile> xmlFiles;
1594         if (!parseChildren(root, MatrixXmlFileConverter{}, &xmlFiles, param)) {
1595             return false;
1596         }
1597         for (auto&& xmlFile : xmlFiles) {
1598             if (!xmlFile.optional()) {
1599                 *param.error = "compatibility-matrix.xmlfile entry " + xmlFile.name() +
1600                                " has to be optional for compatibility matrix version 1.0";
1601                 return false;
1602             }
1603             std::string description{xmlFile.name()};
1604             if (!object->addXmlFile(std::move(xmlFile))) {
1605                 *param.error = "Duplicated compatibility-matrix.xmlfile entry " + description;
1606                 return false;
1607             }
1608         }
1609 
1610         return true;
1611     }
1612 };
1613 
1614 #define CREATE_CONVERT_FN(type)                                         \
1615     std::string toXml(const type& o, SerializeFlags::Type flags) {      \
1616         return type##Converter{}.toXml(o, flags);                       \
1617     }                                                                   \
1618     bool fromXml(type* o, const std::string& xml, std::string* error) { \
1619         return type##Converter{}.fromXml(o, xml, error);                \
1620     }
1621 
1622 // Create convert functions for public usage.
1623 CREATE_CONVERT_FN(HalManifest)
1624 CREATE_CONVERT_FN(CompatibilityMatrix)
1625 
1626 // Create convert functions for internal usage.
1627 CREATE_CONVERT_FN(KernelInfo)
1628 
1629 // Create convert functions for testing.
1630 CREATE_CONVERT_FN(Version)
1631 CREATE_CONVERT_FN(SepolicyVersion)
1632 CREATE_CONVERT_FN(KernelConfigTypedValue)
1633 CREATE_CONVERT_FN(MatrixHal)
1634 CREATE_CONVERT_FN(ManifestHal)
1635 
1636 #undef CREATE_CONVERT_FN
1637 
1638 } // namespace vintf
1639 } // namespace android
1640