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", ®exes, 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, ¶m](
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", ¶m.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", ¶m.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