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 return false;
209 }
210 return this->buildObject(object, root, param);
211 }
212
213 // Public methods for android::vintf::fromXml / android::vintf::toXml.
214 // Serialize |o| into an XML string.
toXmlandroid::vintf::XmlNodeConverter215 inline std::string toXml(const Object& o, SerializeFlags::Type flags) const {
216 DocType* doc = createDocument();
217 appendChild(doc, (*this)(o, MutateNodeParam{doc, flags}));
218 std::string s = printDocument(doc);
219 deleteDocument(doc);
220 return s;
221 }
222 // Deserialize XML string |xml| into |o|.
fromXmlandroid::vintf::XmlNodeConverter223 inline bool fromXml(Object* o, const std::string& xml, std::string* error) const {
224 std::string errorBuffer;
225 if (error == nullptr) error = &errorBuffer;
226
227 auto doc = createDocument(xml);
228 if (doc == nullptr) {
229 *error = "Not a valid XML";
230 return false;
231 }
232 // For top-level <manifest> and <compatibility-matrix>, HalManifestConverter and
233 // CompatibilityMatrixConverter fills in metaversion and pass down to children.
234 // For other nodes, we don't know metaversion of the original XML, so just leave empty
235 // for maximum backwards compatibility.
236 BuildObjectParam buildObjectParam{error, {}, {}};
237 // Pass down filename for the current XML document.
238 if constexpr (std::is_base_of_v<WithFileName, Object>) {
239 // Get the last filename in case `o` keeps the list of filenames
240 std::string_view fileName{o->fileName()};
241 if (auto pos = fileName.rfind(':'); pos != fileName.npos) {
242 fileName.remove_prefix(pos + 1);
243 }
244 buildObjectParam.fileName = std::string(fileName);
245 }
246 bool ret = (*this)(o, getRootChild(doc), buildObjectParam);
247 deleteDocument(doc);
248 return ret;
249 }
250
251 // convenience methods for subclasses to implement virtual functions.
252
253 // All append* functions helps mutateNode() to serialize the object into XML.
254 template <typename T>
appendAttrandroid::vintf::XmlNodeConverter255 inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const {
256 return appendStrAttr(e, attrName, ::android::vintf::to_string(attr));
257 }
258
appendAttrandroid::vintf::XmlNodeConverter259 inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const {
260 return appendStrAttr(e, attrName, attr ? "true" : "false");
261 }
262
263 // text -> <name>text</name>
appendTextElementandroid::vintf::XmlNodeConverter264 inline void appendTextElement(NodeType *parent, const std::string &name,
265 const std::string &text, DocType *d) const {
266 NodeType *c = createNode(name, d);
267 appendText(c, text, d);
268 appendChild(parent, c);
269 }
270
271 // text -> <name>text</name>
272 template<typename Array>
appendTextElementsandroid::vintf::XmlNodeConverter273 inline void appendTextElements(NodeType *parent, const std::string &name,
274 const Array &array, DocType *d) const {
275 for (const std::string &text : array) {
276 NodeType *c = createNode(name, d);
277 appendText(c, text, d);
278 appendChild(parent, c);
279 }
280 }
281
282 template <typename T, typename Array>
appendChildrenandroid::vintf::XmlNodeConverter283 inline void appendChildren(NodeType* parent, const XmlNodeConverter<T>& conv,
284 const Array& array, const MutateNodeParam& param) const {
285 for (const T &t : array) {
286 appendChild(parent, conv(t, param));
287 }
288 }
289
290 // All parse* functions helps buildObject() to deserialize XML to the object. Returns
291 // true if deserialization is successful, false if any error, and "error" will be
292 // set to error message.
293 template <typename T>
parseOptionalAttrandroid::vintf::XmlNodeConverter294 inline bool parseOptionalAttr(NodeType* root, const std::string& attrName, T&& defaultValue,
295 T* attr, std::string* /* error */) const {
296 std::string attrText;
297 bool success = getAttr(root, attrName, &attrText) &&
298 ::android::vintf::parse(attrText, attr);
299 if (!success) {
300 *attr = std::move(defaultValue);
301 }
302 return true;
303 }
304
305 template <typename T>
parseAttrandroid::vintf::XmlNodeConverter306 inline bool parseAttr(NodeType* root, const std::string& attrName, T* attr,
307 std::string* error) const {
308 std::string attrText;
309 bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
310 if (!ret) {
311 *error = "Could not find/parse attr with name \"" + attrName + "\" and value \"" +
312 attrText + "\" for element <" + elementName() + ">";
313 }
314 return ret;
315 }
316
parseAttrandroid::vintf::XmlNodeConverter317 inline bool parseAttr(NodeType* root, const std::string& attrName, std::string* attr,
318 std::string* error) const {
319 bool ret = getAttr(root, attrName, attr);
320 if (!ret) {
321 *error = "Could not find attr with name \"" + attrName + "\" for element <" +
322 elementName() + ">";
323 }
324 return ret;
325 }
326
parseTextElementandroid::vintf::XmlNodeConverter327 inline bool parseTextElement(NodeType* root, const std::string& elementName, std::string* s,
328 std::string* error) const {
329 NodeType *child = getChild(root, elementName);
330 if (child == nullptr) {
331 *error = "Could not find element with name <" + elementName + "> in element <" +
332 this->elementName() + ">";
333 return false;
334 }
335 *s = getText(child);
336 return true;
337 }
338
parseOptionalTextElementandroid::vintf::XmlNodeConverter339 inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName,
340 std::string&& defaultValue, std::string* s,
341 std::string* /* error */) const {
342 NodeType* child = getChild(root, elementName);
343 *s = child == nullptr ? std::move(defaultValue) : getText(child);
344 return true;
345 }
346
parseTextElementsandroid::vintf::XmlNodeConverter347 inline bool parseTextElements(NodeType* root, const std::string& elementName,
348 std::vector<std::string>* v, std::string* /* error */) const {
349 auto nodes = getChildren(root, elementName);
350 v->resize(nodes.size());
351 for (size_t i = 0; i < nodes.size(); ++i) {
352 v->at(i) = getText(nodes[i]);
353 }
354 return true;
355 }
356
357 template <typename T>
parseChildandroid::vintf::XmlNodeConverter358 inline bool parseChild(NodeType* root, const XmlNodeConverter<T>& conv, T* t,
359 const BuildObjectParam& param) const {
360 NodeType *child = getChild(root, conv.elementName());
361 if (child == nullptr) {
362 *param.error = "Could not find element with name <" + conv.elementName() +
363 "> in element <" + this->elementName() + ">";
364 return false;
365 }
366 return conv(t, child, param);
367 }
368
369 template <typename T>
parseOptionalChildandroid::vintf::XmlNodeConverter370 inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
371 T&& defaultValue, T* t, const BuildObjectParam& param) const {
372 NodeType *child = getChild(root, conv.elementName());
373 if (child == nullptr) {
374 *t = std::move(defaultValue);
375 return true;
376 }
377 return conv(t, child, param);
378 }
379
380 template <typename T>
parseOptionalChildandroid::vintf::XmlNodeConverter381 inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
382 std::optional<T>* t, const BuildObjectParam& param) const {
383 NodeType* child = getChild(root, conv.elementName());
384 if (child == nullptr) {
385 *t = std::nullopt;
386 return true;
387 }
388 *t = std::make_optional<T>();
389 return conv(&**t, child, param);
390 }
391
392 template <typename T>
parseChildrenandroid::vintf::XmlNodeConverter393 inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v,
394 const BuildObjectParam& param) const {
395 auto nodes = getChildren(root, conv.elementName());
396 v->resize(nodes.size());
397 for (size_t i = 0; i < nodes.size(); ++i) {
398 if (!conv(&v->at(i), nodes[i], param)) {
399 *param.error = "Could not parse element with name <" + conv.elementName() +
400 "> in element <" + this->elementName() + ">: " + *param.error;
401 return false;
402 }
403 }
404 return true;
405 }
406
407 template <typename Container, typename T = typename Container::value_type,
408 typename = typename Container::key_compare>
parseChildrenandroid::vintf::XmlNodeConverter409 inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, Container* s,
410 const BuildObjectParam& param) const {
411 std::vector<T> vec;
412 if (!parseChildren(root, conv, &vec, param)) {
413 return false;
414 }
415 s->clear();
416 s->insert(vec.begin(), vec.end());
417 if (s->size() != vec.size()) {
418 *param.error = "Duplicated elements <" + conv.elementName() + "> in element <" +
419 this->elementName() + ">";
420 s->clear();
421 return false;
422 }
423 return true;
424 }
425
426 template <typename K, typename V>
parseChildrenandroid::vintf::XmlNodeConverter427 inline bool parseChildren(NodeType* root, const XmlNodeConverter<std::pair<K, V>>& conv,
428 std::map<K, V>* s, const BuildObjectParam& param) const {
429 return parseChildren<std::map<K, V>, std::pair<K, V>>(root, conv, s, param);
430 }
431
parseTextandroid::vintf::XmlNodeConverter432 inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const {
433 *s = getText(node);
434 return true;
435 }
436
437 template <typename T>
parseTextandroid::vintf::XmlNodeConverter438 inline bool parseText(NodeType* node, T* s, std::string* error) const {
439 bool (*parser)(const std::string&, T*) = ::android::vintf::parse;
440 return parseText(node, s, {parser}, error);
441 }
442
443 template <typename T>
parseTextandroid::vintf::XmlNodeConverter444 inline bool parseText(NodeType* node, T* s,
445 const std::function<bool(const std::string&, T*)>& parse,
446 std::string* error) const {
447 std::string text = getText(node);
448 bool ret = parse(text, s);
449 if (!ret) {
450 *error = "Could not parse text \"" + text + "\" in element <" + elementName() + ">";
451 }
452 return ret;
453 }
454 };
455
456 template<typename Object>
457 struct XmlTextConverter : public XmlNodeConverter<Object> {
mutateNodeandroid::vintf::XmlTextConverter458 void mutateNode(const Object& object, NodeType* root,
459 const MutateNodeParam& param) const override {
460 appendText(root, ::android::vintf::to_string(object), param.d);
461 }
buildObjectandroid::vintf::XmlTextConverter462 bool buildObject(Object* object, NodeType* root, const BuildObjectParam& param) const override {
463 return this->parseText(root, object, param.error);
464 }
465 };
466
467 template <typename Pair, typename FirstConverter, typename SecondConverter>
468 struct XmlPairConverter : public XmlNodeConverter<Pair> {
mutateNodeandroid::vintf::XmlPairConverter469 void mutateNode(const Pair& object, NodeType* root,
470 const MutateNodeParam& param) const override {
471 appendChild(root, FirstConverter{}(object.first, param));
472 appendChild(root, SecondConverter{}(object.second, param));
473 }
buildObjectandroid::vintf::XmlPairConverter474 bool buildObject(Pair* object, NodeType* root, const BuildObjectParam& param) const override {
475 return this->parseChild(root, FirstConverter{}, &object->first, param) &&
476 this->parseChild(root, SecondConverter{}, &object->second, param);
477 }
478 };
479
480 // ---------------------- XmlNodeConverter definitions end
481
482 struct VersionConverter : public XmlTextConverter<Version> {
elementNameandroid::vintf::VersionConverter483 std::string elementName() const override { return "version"; }
484 };
485
486 struct SepolicyVersionConverter : public XmlTextConverter<SepolicyVersion> {
elementNameandroid::vintf::SepolicyVersionConverter487 std::string elementName() const override { return "version"; }
488 };
489
490 struct VersionRangeConverter : public XmlTextConverter<VersionRange> {
elementNameandroid::vintf::VersionRangeConverter491 std::string elementName() const override { return "version"; }
492 };
493
494 struct SepolicyVersionRangeConverter : public XmlTextConverter<SepolicyVersionRange> {
elementNameandroid::vintf::SepolicyVersionRangeConverter495 std::string elementName() const override { return "sepolicy-version"; }
496 };
497
498 // <version>100</version> <=> Version{kFakeAidlMajorVersion, 100}
499 struct AidlVersionConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::AidlVersionConverter500 std::string elementName() const override { return "version"; }
mutateNodeandroid::vintf::AidlVersionConverter501 void mutateNode(const Version& object, NodeType* root,
502 const MutateNodeParam& param) const override {
503 appendText(root, aidlVersionToString(object), param.d);
504 }
buildObjectandroid::vintf::AidlVersionConverter505 bool buildObject(Version* object, NodeType* root,
506 const BuildObjectParam& param) const override {
507 return parseText(root, object, {parseAidlVersion}, param.error);
508 }
509 };
510
511 // <version>100</version> <=> VersionRange{kFakeAidlMajorVersion, 100, 100}
512 // <version>100-105</version> <=> VersionRange{kFakeAidlMajorVersion, 100, 105}
513 struct AidlVersionRangeConverter : public XmlNodeConverter<VersionRange> {
elementNameandroid::vintf::AidlVersionRangeConverter514 std::string elementName() const override { return "version"; }
mutateNodeandroid::vintf::AidlVersionRangeConverter515 void mutateNode(const VersionRange& object, NodeType* root,
516 const MutateNodeParam& param) const override {
517 appendText(root, aidlVersionRangeToString(object), param.d);
518 }
buildObjectandroid::vintf::AidlVersionRangeConverter519 bool buildObject(VersionRange* object, NodeType* root,
520 const BuildObjectParam& param) const override {
521 return parseText(root, object, {parseAidlVersionRange}, param.error);
522 }
523 };
524
525 struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
elementNameandroid::vintf::TransportArchConverter526 std::string elementName() const override { return "transport"; }
mutateNodeandroid::vintf::TransportArchConverter527 void mutateNode(const TransportArch& object, NodeType* root,
528 const MutateNodeParam& param) const override {
529 if (object.arch != Arch::ARCH_EMPTY) {
530 appendAttr(root, "arch", object.arch);
531 }
532 if (object.ip.has_value()) {
533 appendAttr(root, "ip", *object.ip);
534 }
535 if (object.port.has_value()) {
536 appendAttr(root, "port", *object.port);
537 }
538 appendText(root, ::android::vintf::to_string(object.transport), param.d);
539 }
buildObjectandroid::vintf::TransportArchConverter540 bool buildObject(TransportArch* object, NodeType* root,
541 const BuildObjectParam& param) const override {
542 if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, param.error) ||
543 !parseOptionalAttr(root, "ip", {}, &object->ip, param.error) ||
544 !parseOptionalAttr(root, "port", {}, &object->port, param.error) ||
545 !parseText(root, &object->transport, param.error)) {
546 return false;
547 }
548 if (!object->isValid(param.error)) {
549 return false;
550 }
551 return true;
552 }
553 };
554
555 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
elementNameandroid::vintf::KernelConfigTypedValueConverter556 std::string elementName() const override { return "value"; }
mutateNodeandroid::vintf::KernelConfigTypedValueConverter557 void mutateNode(const KernelConfigTypedValue& object, NodeType* root,
558 const MutateNodeParam& param) const override {
559 appendAttr(root, "type", object.mType);
560 appendText(root, ::android::vintf::to_string(object), param.d);
561 }
buildObjectandroid::vintf::KernelConfigTypedValueConverter562 bool buildObject(KernelConfigTypedValue* object, NodeType* root,
563 const BuildObjectParam& param) const override {
564 std::string stringValue;
565 if (!parseAttr(root, "type", &object->mType, param.error) ||
566 !parseText(root, &stringValue, param.error)) {
567 return false;
568 }
569 if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
570 *param.error = "Could not parse kernel config value \"" + stringValue + "\"";
571 return false;
572 }
573 return true;
574 }
575 };
576
577 struct KernelConfigKeyConverter : public XmlTextConverter<KernelConfigKey> {
elementNameandroid::vintf::KernelConfigKeyConverter578 std::string elementName() const override { return "key"; }
579 };
580
581 struct MatrixKernelConfigConverter : public XmlPairConverter<KernelConfig, KernelConfigKeyConverter,
582 KernelConfigTypedValueConverter> {
elementNameandroid::vintf::MatrixKernelConfigConverter583 std::string elementName() const override { return "config"; }
584 };
585
586 struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
elementNameandroid::vintf::HalInterfaceConverter587 std::string elementName() const override { return "interface"; }
mutateNodeandroid::vintf::HalInterfaceConverter588 void mutateNode(const HalInterface& object, NodeType* root,
589 const MutateNodeParam& param) const override {
590 if (!object.name().empty()) {
591 appendTextElement(root, "name", object.name(), param.d);
592 }
593 appendTextElements(root, "instance", object.mInstances, param.d);
594 appendTextElements(root, "regex-instance", object.mRegexes, param.d);
595 }
buildObjectandroid::vintf::HalInterfaceConverter596 bool buildObject(HalInterface* object, NodeType* root,
597 const BuildObjectParam& param) const override {
598 std::vector<std::string> instances;
599 std::vector<std::string> regexes;
600 if (!parseOptionalTextElement(root, "name", {}, &object->mName, param.error) ||
601 !parseTextElements(root, "instance", &instances, param.error) ||
602 !parseTextElements(root, "regex-instance", ®exes, param.error)) {
603 return false;
604 }
605 bool success = true;
606 for (const auto& e : instances) {
607 if (!object->insertInstance(e, false /* isRegex */)) {
608 if (!param.error->empty()) *param.error += "\n";
609 *param.error += "Duplicated instance '" + e + "' in " + object->name();
610 success = false;
611 }
612 }
613 for (const auto& e : regexes) {
614 details::Regex regex;
615 if (!regex.compile(e)) {
616 if (!param.error->empty()) *param.error += "\n";
617 *param.error += "Invalid regular expression '" + e + "' in " + object->name();
618 success = false;
619 }
620 if (!object->insertInstance(e, true /* isRegex */)) {
621 if (!param.error->empty()) *param.error += "\n";
622 *param.error += "Duplicated regex-instance '" + e + "' in " + object->name();
623 success = false;
624 }
625 }
626 return success;
627 }
628 };
629
630 struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
elementNameandroid::vintf::MatrixHalConverter631 std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::MatrixHalConverter632 void mutateNode(const MatrixHal& object, NodeType* root,
633 const MutateNodeParam& param) const override {
634 appendAttr(root, "format", object.format);
635 appendAttr(root, "optional", object.optional);
636 // Only include update-via-apex if enabled
637 if (object.updatableViaApex) {
638 appendAttr(root, "updatable-via-apex", object.updatableViaApex);
639 }
640 appendTextElement(root, "name", object.name, param.d);
641 if (object.format == HalFormat::AIDL) {
642 // By default, buildObject() assumes a <version>0</version> tag if no <version> tag
643 // is specified. Don't output any <version> tag if there's only one <version>0</version>
644 // tag.
645 if (object.versionRanges.size() != 1 ||
646 object.versionRanges[0] != details::kDefaultAidlVersionRange) {
647 appendChildren(root, AidlVersionRangeConverter{}, object.versionRanges, param);
648 }
649 } else {
650 appendChildren(root, VersionRangeConverter{}, object.versionRanges, param);
651 }
652 appendChildren(root, HalInterfaceConverter{}, iterateValues(object.interfaces), param);
653 }
buildObjectandroid::vintf::MatrixHalConverter654 bool buildObject(MatrixHal* object, NodeType* root,
655 const BuildObjectParam& param) const override {
656 std::vector<HalInterface> interfaces;
657 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, param.error) ||
658 !parseOptionalAttr(root, "optional", true /* defaultValue */, &object->optional,
659 param.error) ||
660 !parseOptionalAttr(root, "updatable-via-apex", false /* defaultValue */,
661 &object->updatableViaApex, param.error) ||
662 !parseTextElement(root, "name", &object->name, param.error) ||
663 !parseChildren(root, HalInterfaceConverter{}, &interfaces, param)) {
664 return false;
665 }
666 if (object->format == HalFormat::AIDL) {
667 if (!parseChildren(root, AidlVersionRangeConverter{}, &object->versionRanges, param)) {
668 return false;
669 }
670 // Insert fake version for AIDL HALs so that compatibility check for AIDL and other
671 // HAL formats can be unified.
672 if (object->versionRanges.empty()) {
673 object->versionRanges.push_back(details::kDefaultAidlVersionRange);
674 }
675 } else {
676 if (!parseChildren(root, VersionRangeConverter{}, &object->versionRanges, param)) {
677 return false;
678 }
679 }
680 for (auto&& interface : interfaces) {
681 std::string name{interface.name()};
682 auto res = object->interfaces.emplace(std::move(name), std::move(interface));
683 if (!res.second) {
684 *param.error = "Duplicated interface entry \"" + res.first->first +
685 "\"; if additional instances are needed, add them to the "
686 "existing <interface> node.";
687 return false;
688 }
689 }
690 if (!checkAdditionalRestrictionsOnHal(*object, param.error)) {
691 return false;
692 }
693
694 if (!object->isValid(param.error)) {
695 param.error->insert(0, "'" + object->name + "' is not a valid Matrix HAL: ");
696 return false;
697 }
698 return true;
699 }
700
701 private:
checkAdditionalRestrictionsOnHalandroid::vintf::MatrixHalConverter702 bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal, std::string* error) const {
703 // Do not check for target-side libvintf to avoid restricting ability for upgrade
704 // accidentally.
705 if constexpr (kDevice) {
706 return true;
707 }
708 if (hal.getName() == "netutils-wrapper") {
709 if (hal.versionRanges.size() != 1) {
710 *error =
711 "netutils-wrapper HAL must specify exactly one version x.0, "
712 "but multiple <version> element is specified.";
713 return false;
714 }
715 const VersionRange& v = hal.versionRanges.at(0);
716 if (!v.isSingleVersion()) {
717 *error =
718 "netutils-wrapper HAL must specify exactly one version x.0, "
719 "but a range is provided. Perhaps you mean '" +
720 to_string(Version{v.majorVer, 0}) + "'?";
721 return false;
722 }
723 if (v.minMinor != 0) {
724 *error =
725 "netutils-wrapper HAL must specify exactly one version x.0, "
726 "but minor version is not 0. Perhaps you mean '" +
727 to_string(Version{v.majorVer, 0}) + "'?";
728 return false;
729 }
730 }
731 return true;
732 }
733 };
734
735 struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> {
elementNameandroid::vintf::MatrixKernelConditionsConverter736 std::string elementName() const override { return "conditions"; }
mutateNodeandroid::vintf::MatrixKernelConditionsConverter737 void mutateNode(const std::vector<KernelConfig>& object, NodeType* root,
738 const MutateNodeParam& param) const override {
739 appendChildren(root, MatrixKernelConfigConverter{}, object, param);
740 }
buildObjectandroid::vintf::MatrixKernelConditionsConverter741 bool buildObject(std::vector<KernelConfig>* object, NodeType* root,
742 const BuildObjectParam& param) const override {
743 return parseChildren(root, MatrixKernelConfigConverter{}, object, param);
744 }
745 };
746
747 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
elementNameandroid::vintf::MatrixKernelConverter748 std::string elementName() const override { return "kernel"; }
mutateNodeandroid::vintf::MatrixKernelConverter749 void mutateNode(const MatrixKernel& object, NodeType* root,
750 const MutateNodeParam& param) const override {
751 KernelVersion kv = object.mMinLts;
752 if (!param.flags.isKernelMinorRevisionEnabled()) {
753 kv.minorRev = 0u;
754 }
755 appendAttr(root, "version", kv);
756
757 if (object.getSourceMatrixLevel() != Level::UNSPECIFIED) {
758 appendAttr(root, "level", object.getSourceMatrixLevel());
759 }
760
761 if (!object.mConditions.empty()) {
762 appendChild(root, MatrixKernelConditionsConverter{}(object.mConditions, param));
763 }
764 if (param.flags.isKernelConfigsEnabled()) {
765 appendChildren(root, MatrixKernelConfigConverter{}, object.mConfigs, param);
766 }
767 }
buildObjectandroid::vintf::MatrixKernelConverter768 bool buildObject(MatrixKernel* object, NodeType* root,
769 const BuildObjectParam& param) const override {
770 Level sourceMatrixLevel = Level::UNSPECIFIED;
771 if (!parseAttr(root, "version", &object->mMinLts, param.error) ||
772 !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &sourceMatrixLevel,
773 param.error) ||
774 !parseOptionalChild(root, MatrixKernelConditionsConverter{}, {}, &object->mConditions,
775 param) ||
776 !parseChildren(root, MatrixKernelConfigConverter{}, &object->mConfigs, param)) {
777 return false;
778 }
779 object->setSourceMatrixLevel(sourceMatrixLevel);
780 return true;
781 }
782 };
783
784 struct FqInstanceConverter : public XmlTextConverter<FqInstance> {
elementNameandroid::vintf::FqInstanceConverter785 std::string elementName() const override { return "fqname"; }
786 };
787
788 // Convert ManifestHal from and to XML. Returned object is guaranteed to have
789 // .isValid() == true.
790 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
elementNameandroid::vintf::ManifestHalConverter791 std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::ManifestHalConverter792 void mutateNode(const ManifestHal& object, NodeType* root,
793 const MutateNodeParam& param) const override {
794 appendAttr(root, "format", object.format);
795 appendTextElement(root, "name", object.name, param.d);
796 if (!object.transportArch.empty()) {
797 appendChild(root, TransportArchConverter{}(object.transportArch, param));
798 }
799 if (object.format == HalFormat::AIDL) {
800 // By default, buildObject() assumes a <version>0</version> tag if no <version> tag
801 // is specified. Don't output any <version> tag if there's only one <version>0</version>
802 // tag.
803 if (object.versions.size() != 1 || object.versions[0] != details::kDefaultAidlVersion) {
804 appendChildren(root, AidlVersionConverter{}, object.versions, param);
805 }
806 } else {
807 appendChildren(root, VersionConverter{}, object.versions, param);
808 }
809 if (object.isOverride()) {
810 appendAttr(root, "override", object.isOverride());
811 }
812 if (const auto& apex = object.updatableViaApex(); apex.has_value()) {
813 appendAttr(root, "updatable-via-apex", apex.value());
814 }
815 if (param.flags.isFqnameEnabled()) {
816 std::set<std::string> simpleFqInstances;
817 object.forEachInstance([&simpleFqInstances](const auto& manifestInstance) {
818 simpleFqInstances.emplace(manifestInstance.getSimpleFqInstance());
819 return true;
820 });
821 appendTextElements(root, FqInstanceConverter{}.elementName(), simpleFqInstances,
822 param.d);
823 }
824 if (object.getMaxLevel() != Level::UNSPECIFIED) {
825 appendAttr(root, "max-level", object.getMaxLevel());
826 }
827 if (object.getMinLevel() != Level::UNSPECIFIED) {
828 appendAttr(root, "min-level", object.getMinLevel());
829 }
830 }
buildObjectandroid::vintf::ManifestHalConverter831 bool buildObject(ManifestHal* object, NodeType* root,
832 const BuildObjectParam& param) const override {
833 std::vector<HalInterface> interfaces;
834 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, param.error) ||
835 !parseOptionalAttr(root, "override", false, &object->mIsOverride, param.error) ||
836 !parseOptionalAttr(root, "updatable-via-apex", {}, &object->mUpdatableViaApex,
837 param.error) ||
838 !parseTextElement(root, "name", &object->name, param.error) ||
839 !parseOptionalChild(root, TransportArchConverter{}, {}, &object->transportArch,
840 param) ||
841 !parseOptionalAttr(root, "max-level", Level::UNSPECIFIED, &object->mMaxLevel,
842 param.error) ||
843 !parseOptionalAttr(root, "min-level", Level::UNSPECIFIED, &object->mMinLevel,
844 param.error)) {
845 return false;
846 }
847
848 std::string_view apexName = parseApexName(param.fileName);
849 if (!apexName.empty()) {
850 if (object->mUpdatableViaApex.has_value()) {
851 // When defined in APEX, updatable-via-apex can be either
852 // - ""(empty) : the HAL isn't updatable even if it's in APEX
853 // - {apex name}: the HAL is updtable via the current APEX
854 const std::string& updatableViaApex = object->mUpdatableViaApex.value();
855 if (!updatableViaApex.empty() && apexName.compare(updatableViaApex) != 0) {
856 *param.error = "Invalid APEX HAL " + object->name + ": updatable-via-apex " +
857 updatableViaApex + " doesn't match with the defining APEX " +
858 std::string(apexName) + "\n";
859 return false;
860 }
861 } else {
862 // Set updatable-via-apex to the defining APEX when it's not set explicitly.
863 // This should be set before calling insertInstances() which copies the current
864 // value to ManifestInstance.
865 object->mUpdatableViaApex = apexName;
866 }
867 }
868
869 switch (object->format) {
870 case HalFormat::HIDL: {
871 if (!parseChildren(root, VersionConverter{}, &object->versions, param))
872 return false;
873 if (object->transportArch.empty()) {
874 *param.error =
875 "HIDL HAL '" + object->name + "' should have <transport> defined.";
876 return false;
877 }
878 if (object->transportArch.transport == Transport::INET ||
879 object->transportArch.ip.has_value() ||
880 object->transportArch.port.has_value()) {
881 *param.error = "HIDL HAL '" + object->name +
882 "' should not have <transport> \"inet\" " +
883 "or ip or port attributes defined.";
884 return false;
885 }
886 } break;
887 case HalFormat::NATIVE: {
888 if (!parseChildren(root, VersionConverter{}, &object->versions, param))
889 return false;
890 if (!object->transportArch.empty()) {
891 *param.error =
892 "Native HAL '" + object->name + "' should not have <transport> defined.";
893 return false;
894 }
895 } break;
896 case HalFormat::AIDL: {
897 if (!object->transportArch.empty() &&
898 object->transportArch.transport != Transport::INET) {
899 if (param.metaVersion >= kMetaVersionAidlInet) {
900 *param.error = "AIDL HAL '" + object->name +
901 R"(' only supports "inet" or empty <transport>, found ")" +
902 to_string(object->transportArch) + "\"";
903 return false;
904 }
905 LOG(WARNING) << "Ignoring <transport> on manifest <hal format=\"aidl\"> "
906 << object->name << ". Only \"inet\" supported.";
907 object->transportArch = {};
908 }
909 if (!parseChildren(root, AidlVersionConverter{}, &object->versions, param)) {
910 return false;
911 }
912 // Insert fake version for AIDL HALs so that forEachInstance works.
913 if (object->versions.empty()) {
914 object->versions.push_back(details::kDefaultAidlVersion);
915 }
916 } break;
917 default: {
918 LOG(FATAL) << "Unhandled HalFormat "
919 << static_cast<typename std::underlying_type<HalFormat>::type>(
920 object->format);
921 } break;
922 }
923 if (!object->transportArch.isValid(param.error)) return false;
924
925 // Parse <fqname> into fqInstances list
926 std::set<FqInstance> fqInstances;
927 if (!parseChildren(root, FqInstanceConverter{}, &fqInstances, param)) {
928 return false;
929 }
930
931 // Handle deprecated <interface> x <instance>
932 if (!parseChildren(root, HalInterfaceConverter{}, &interfaces, param)) {
933 return false;
934 }
935 // Check duplicated <interface><name>
936 std::set<std::string> interface_names;
937 for (auto &&interface : interfaces) {
938 auto res = interface_names.emplace(interface.name());
939 if (!res.second) {
940 *param.error = "Duplicated interface entry \"" + *res.first +
941 "\"; if additional instances are needed, add them to the "
942 "existing <interface> node.";
943 return false;
944 }
945 }
946 // Turn <version> x <interface> x <instance> into <fqname>s; insert into
947 // fqInstances list.
948 bool convertedInstancesIntoFqnames = false;
949 for (const auto& v : object->versions) {
950 for (const auto& intf : interfaces) {
951 if (param.metaVersion >= kMetaVersionNoHalInterfaceInstance &&
952 (object->format == HalFormat::HIDL || object->format == HalFormat::AIDL) &&
953 !intf.hasAnyInstance()) {
954 *param.error +=
955 "<hal> " + object->name + " <interface> " + intf.name() +
956 " has no <instance>. Either specify <instance> or, "
957 "preferably, specify <fqname> and delete <version> and <interface>.";
958 return false;
959 }
960 bool cont = intf.forEachInstance(
961 [&v, &fqInstances, &convertedInstancesIntoFqnames, &object, ¶m](
962 const auto& interface, const auto& instance, bool /* isRegex */) {
963 auto fqInstance = details::convertLegacyInstanceIntoFqInstance(
964 object->name, v, interface, instance, object->format, param.error);
965
966 if (!fqInstance.has_value()) {
967 return false;
968 }
969
970 // Check for duplication in fqInstances.
971 // Before kMetaVersionNoHalInterfaceInstance: It is okay to have duplication
972 // between <interface> and <fqname>.
973 // After kMetaVersionNoHalInterfaceInstance: Duplication between
974 // <interface> and <fqname> is not allowed.
975 auto&& [it, inserted] = fqInstances.emplace(std::move(fqInstance.value()));
976 if (param.metaVersion >= kMetaVersionNoHalInterfaceInstance && !inserted) {
977 std::string debugString =
978 object->format == HalFormat::AIDL
979 ? toAidlFqnameString(object->name, interface, instance)
980 : toFQNameString(object->name, v, interface, instance);
981 *param.error = "Duplicated " + debugString +
982 " in <interface><instance> and <fqname>. ";
983 if constexpr (kDevice) {
984 *param.error +=
985 "(Did you copy source manifests to the device directly "
986 "without going through assemble_vintf, e.g. not using "
987 "DEVICE_MANIFEST_FILE or ODM_MANIFEST_FILES?)";
988 } else {
989 *param.error += "Remove deprecated <interface>.";
990 }
991 return false;
992 }
993
994 convertedInstancesIntoFqnames = true;
995 return true; // continue
996 });
997 if (!cont) {
998 return false;
999 }
1000 }
1001 }
1002
1003 if (!checkAdditionalRestrictionsOnHal(*object, param.error)) {
1004 return false;
1005 }
1006
1007 // For HIDL, if any <version> x <interface> x <instance> tuple, all <version>
1008 // tags can be cleared. <version> information is already in <fqname>'s.
1009 // For AIDL, <version> information is not in <fqname>, so don't clear them.
1010 // For HALs with only <version> but no <interface>
1011 // (e.g. native HALs like netutils-wrapper), <version> is kept.
1012 if (convertedInstancesIntoFqnames && object->format != HalFormat::AIDL) {
1013 object->versions.clear();
1014 }
1015
1016 std::set<FqInstance> fqInstancesToInsert;
1017 for (auto& e : fqInstances) {
1018 if (e.hasPackage()) {
1019 *param.error = "Should not specify package: \"" + e.string() + "\"";
1020 return false;
1021 }
1022 if (object->format == HalFormat::AIDL) {
1023 // <fqname> in AIDL HALs should not contain version.
1024 if (e.hasVersion()) {
1025 *param.error = "Should not specify version in <fqname> for AIDL HAL: \"" +
1026 e.string() + "\"";
1027 return false;
1028 }
1029 // Put in the fake kDefaultAidlVersion so that HalManifest can
1030 // store it in an FqInstance object with a non-empty package.
1031 FqInstance withFakeVersion;
1032 if (!withFakeVersion.setTo(details::kDefaultAidlVersion.majorVer,
1033 details::kDefaultAidlVersion.minorVer, e.getInterface(),
1034 e.getInstance())) {
1035 return false;
1036 }
1037 fqInstancesToInsert.emplace(std::move(withFakeVersion));
1038 } else {
1039 fqInstancesToInsert.emplace(std::move(e));
1040 }
1041 }
1042
1043 if (param.metaVersion >= kMetaVersionNoHalInterfaceInstance &&
1044 (object->format == HalFormat::HIDL || object->format == HalFormat::AIDL) &&
1045 fqInstancesToInsert.empty() && !object->isOverride()) {
1046 *param.error = "<hal> " + object->name + " has no instance. Fix by adding <fqname>.";
1047 return false;
1048 }
1049
1050 bool allowMajorVersionDup = param.metaVersion < kMetaVersionNoHalInterfaceInstance;
1051 if (!object->insertInstances(fqInstancesToInsert, allowMajorVersionDup, param.error)) {
1052 return false;
1053 }
1054
1055 if (!object->isValid(param.error)) {
1056 param.error->insert(0, "'" + object->name + "' is not a valid Manifest HAL: ");
1057 return false;
1058 }
1059
1060 return true;
1061 }
1062
1063 private:
checkAdditionalRestrictionsOnHalandroid::vintf::ManifestHalConverter1064 bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal, std::string* error) const {
1065 // Do not check for target-side libvintf to avoid restricting upgrade accidentally.
1066 if constexpr (kDevice) {
1067 return true;
1068 }
1069 if (hal.getName() == "netutils-wrapper") {
1070 for (const Version& v : hal.versions) {
1071 if (v.minorVer != 0) {
1072 *error =
1073 "netutils-wrapper HAL must specify exactly one version x.0, "
1074 "but minor version is not 0. Perhaps you mean '" +
1075 to_string(Version{v.majorVer, 0}) + "'?";
1076 return false;
1077 }
1078 }
1079 }
1080 return true;
1081 }
1082 };
1083
1084 struct KernelSepolicyVersionConverter : public XmlTextConverter<KernelSepolicyVersion> {
elementNameandroid::vintf::KernelSepolicyVersionConverter1085 std::string elementName() const override { return "kernel-sepolicy-version"; }
1086 };
1087
1088 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
elementNameandroid::vintf::SepolicyConverter1089 std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::SepolicyConverter1090 void mutateNode(const Sepolicy& object, NodeType* root,
1091 const MutateNodeParam& param) const override {
1092 appendChild(root, KernelSepolicyVersionConverter{}(object.kernelSepolicyVersion(), param));
1093 appendChildren(root, SepolicyVersionRangeConverter{}, object.sepolicyVersions(), param);
1094 }
buildObjectandroid::vintf::SepolicyConverter1095 bool buildObject(Sepolicy* object, NodeType* root,
1096 const BuildObjectParam& param) const override {
1097 if (!parseChild(root, KernelSepolicyVersionConverter{}, &object->mKernelSepolicyVersion,
1098 param) ||
1099 !parseChildren(root, SepolicyVersionRangeConverter{}, &object->mSepolicyVersionRanges,
1100 param)) {
1101 return false;
1102 }
1103 return true;
1104 }
1105 };
1106
1107 struct [[deprecated]] VndkVersionRangeConverter : public XmlTextConverter<VndkVersionRange> {
elementNameandroid::vintf::VndkVersionRangeConverter1108 std::string elementName() const override { return "version"; }
1109 };
1110
1111 struct VndkVersionConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::VndkVersionConverter1112 std::string elementName() const override { return "version"; }
1113 };
1114
1115 struct VndkLibraryConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::VndkLibraryConverter1116 std::string elementName() const override { return "library"; }
1117 };
1118
1119 struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> {
elementNameandroid::vintf::VndkConverter1120 std::string elementName() const override { return "vndk"; }
mutateNodeandroid::vintf::VndkConverter1121 void mutateNode(const Vndk& object, NodeType* root,
1122 const MutateNodeParam& param) const override {
1123 appendChild(root, VndkVersionRangeConverter{}(object.mVersionRange, param));
1124 appendChildren(root, VndkLibraryConverter{}, object.mLibraries, param);
1125 }
buildObjectandroid::vintf::VndkConverter1126 bool buildObject(Vndk* object, NodeType* root, const BuildObjectParam& param) const override {
1127 if (!parseChild(root, VndkVersionRangeConverter{}, &object->mVersionRange, param) ||
1128 !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, param)) {
1129 return false;
1130 }
1131 return true;
1132 }
1133 };
1134
1135 struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> {
elementNameandroid::vintf::VendorNdkConverter1136 std::string elementName() const override { return "vendor-ndk"; }
mutateNodeandroid::vintf::VendorNdkConverter1137 void mutateNode(const VendorNdk& object, NodeType* root,
1138 const MutateNodeParam& param) const override {
1139 appendChild(root, VndkVersionConverter{}(object.mVersion, param));
1140 appendChildren(root, VndkLibraryConverter{}, object.mLibraries, param);
1141 }
buildObjectandroid::vintf::VendorNdkConverter1142 bool buildObject(VendorNdk* object, NodeType* root,
1143 const BuildObjectParam& param) const override {
1144 if (!parseChild(root, VndkVersionConverter{}, &object->mVersion, param) ||
1145 !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, param)) {
1146 return false;
1147 }
1148 return true;
1149 }
1150 };
1151
1152 struct SystemSdkVersionConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::SystemSdkVersionConverter1153 std::string elementName() const override { return "version"; }
1154 };
1155
1156 struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> {
elementNameandroid::vintf::SystemSdkConverter1157 std::string elementName() const override { return "system-sdk"; }
mutateNodeandroid::vintf::SystemSdkConverter1158 void mutateNode(const SystemSdk& object, NodeType* root,
1159 const MutateNodeParam& param) const override {
1160 appendChildren(root, SystemSdkVersionConverter{}, object.versions(), param);
1161 }
buildObjectandroid::vintf::SystemSdkConverter1162 bool buildObject(SystemSdk* object, NodeType* root,
1163 const BuildObjectParam& param) const override {
1164 return parseChildren(root, SystemSdkVersionConverter{}, &object->mVersions, param);
1165 }
1166 };
1167
1168 struct HalManifestSepolicyConverter : public XmlNodeConverter<SepolicyVersion> {
elementNameandroid::vintf::HalManifestSepolicyConverter1169 std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::HalManifestSepolicyConverter1170 void mutateNode(const SepolicyVersion& object, NodeType* root,
1171 const MutateNodeParam& param) const override {
1172 appendChild(root, SepolicyVersionConverter{}(object, param));
1173 }
buildObjectandroid::vintf::HalManifestSepolicyConverter1174 bool buildObject(SepolicyVersion* object, NodeType* root,
1175 const BuildObjectParam& param) const override {
1176 return parseChild(root, SepolicyVersionConverter{}, object, param);
1177 }
1178 };
1179
1180 struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> {
elementNameandroid::vintf::ManifestXmlFileConverter1181 std::string elementName() const override { return "xmlfile"; }
mutateNodeandroid::vintf::ManifestXmlFileConverter1182 void mutateNode(const ManifestXmlFile& object, NodeType* root,
1183 const MutateNodeParam& param) const override {
1184 appendTextElement(root, "name", object.name(), param.d);
1185 appendChild(root, VersionConverter{}(object.version(), param));
1186 if (!object.overriddenPath().empty()) {
1187 appendTextElement(root, "path", object.overriddenPath(), param.d);
1188 }
1189 }
buildObjectandroid::vintf::ManifestXmlFileConverter1190 bool buildObject(ManifestXmlFile* object, NodeType* root,
1191 const BuildObjectParam& param) const override {
1192 if (!parseTextElement(root, "name", &object->mName, param.error) ||
1193 !parseChild(root, VersionConverter{}, &object->mVersion, param) ||
1194 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, param.error)) {
1195 return false;
1196 }
1197 return true;
1198 }
1199 };
1200
1201 struct StringKernelConfigKeyConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::StringKernelConfigKeyConverter1202 std::string elementName() const override { return "key"; }
1203 };
1204
1205 struct KernelConfigValueConverter : public XmlTextConverter<std::string> {
elementNameandroid::vintf::KernelConfigValueConverter1206 std::string elementName() const override { return "value"; }
1207 };
1208
1209 struct StringKernelConfigConverter
1210 : public XmlPairConverter<std::pair<std::string, std::string>, StringKernelConfigKeyConverter,
1211 KernelConfigValueConverter> {
elementNameandroid::vintf::StringKernelConfigConverter1212 std::string elementName() const override { return "config"; }
1213 };
1214
1215 struct KernelInfoConverter : public XmlNodeConverter<KernelInfo> {
elementNameandroid::vintf::KernelInfoConverter1216 std::string elementName() const override { return "kernel"; }
mutateNodeandroid::vintf::KernelInfoConverter1217 void mutateNode(const KernelInfo& object, NodeType* root,
1218 const MutateNodeParam& param) const override {
1219 if (object.version() != KernelVersion{}) {
1220 appendAttr(root, "version", object.version());
1221 }
1222 if (object.level() != Level::UNSPECIFIED) {
1223 appendAttr(root, "target-level", object.level());
1224 }
1225 if (param.flags.isKernelConfigsEnabled()) {
1226 appendChildren(root, StringKernelConfigConverter{}, object.configs(), param);
1227 }
1228 }
buildObjectandroid::vintf::KernelInfoConverter1229 bool buildObject(KernelInfo* object, NodeType* root,
1230 const BuildObjectParam& param) const override {
1231 return parseOptionalAttr(root, "version", {}, &object->mVersion, param.error) &&
1232 parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
1233 param.error) &&
1234 parseChildren(root, StringKernelConfigConverter{}, &object->mConfigs, param);
1235 }
1236 };
1237
1238 struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
elementNameandroid::vintf::HalManifestConverter1239 std::string elementName() const override { return "manifest"; }
mutateNodeandroid::vintf::HalManifestConverter1240 void mutateNode(const HalManifest& object, NodeType* root,
1241 const MutateNodeParam& param) const override {
1242 if (param.flags.isMetaVersionEnabled()) {
1243 // Append the current metaversion of libvintf because the XML file
1244 // is generated with libvintf @ current meta version.
1245 appendAttr(root, "version", kMetaVersion);
1246 }
1247 if (param.flags.isSchemaTypeEnabled()) {
1248 appendAttr(root, "type", object.mType);
1249 }
1250
1251 if (param.flags.isHalsEnabled()) {
1252 appendChildren(root, ManifestHalConverter{}, object.getHals(), param);
1253 }
1254 if (object.mType == SchemaType::DEVICE) {
1255 if (param.flags.isSepolicyEnabled()) {
1256 if (object.device.mSepolicyVersion != SepolicyVersion{}) {
1257 appendChild(root, HalManifestSepolicyConverter{}(object.device.mSepolicyVersion,
1258 param));
1259 }
1260 }
1261 if (object.mLevel != Level::UNSPECIFIED) {
1262 this->appendAttr(root, "target-level", object.mLevel);
1263 }
1264
1265 if (param.flags.isKernelEnabled()) {
1266 if (!!object.kernel()) {
1267 appendChild(root, KernelInfoConverter{}(*object.kernel(), param));
1268 }
1269 }
1270 } else if (object.mType == SchemaType::FRAMEWORK) {
1271 if (param.flags.isVndkEnabled()) {
1272 #pragma clang diagnostic push
1273 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1274 appendChildren(root, VndkConverter{}, object.framework.mVndks, param);
1275 #pragma clang diagnostic pop
1276
1277 appendChildren(root, VendorNdkConverter{}, object.framework.mVendorNdks, param);
1278 }
1279 if (param.flags.isSsdkEnabled()) {
1280 if (!object.framework.mSystemSdk.empty()) {
1281 appendChild(root, SystemSdkConverter{}(object.framework.mSystemSdk, param));
1282 }
1283 }
1284 }
1285
1286 if (param.flags.isXmlFilesEnabled()) {
1287 appendChildren(root, ManifestXmlFileConverter{}, object.getXmlFiles(), param);
1288 }
1289 }
buildObjectandroid::vintf::HalManifestConverter1290 bool buildObject(HalManifest* object, NodeType* root,
1291 const BuildObjectParam& constParam) const override {
1292 BuildObjectParam param = constParam;
1293 if (!parseAttr(root, "version", ¶m.metaVersion, param.error)) return false;
1294 if (param.metaVersion > kMetaVersion) {
1295 *param.error = "Unrecognized manifest.version " + to_string(param.metaVersion) +
1296 " (libvintf@" + to_string(kMetaVersion) + ")";
1297 return false;
1298 }
1299 object->mSourceMetaVersion = param.metaVersion;
1300
1301 if (!parseAttr(root, "type", &object->mType, param.error)) {
1302 return false;
1303 }
1304
1305 std::vector<ManifestHal> hals;
1306 if (!parseChildren(root, ManifestHalConverter{}, &hals, param)) {
1307 return false;
1308 }
1309 for (auto&& hal : hals) {
1310 hal.setFileName(object->fileName());
1311 }
1312
1313 if (object->mType == SchemaType::DEVICE) {
1314 // tags for device hal manifest only.
1315 // <sepolicy> can be missing because it can be determined at build time, not hard-coded
1316 // in the XML file.
1317 if (!parseOptionalChild(root, HalManifestSepolicyConverter{}, {},
1318 &object->device.mSepolicyVersion, param)) {
1319 return false;
1320 }
1321
1322 if (!parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
1323 param.error)) {
1324 return false;
1325 }
1326
1327 if (!parseOptionalChild(root, KernelInfoConverter{}, &object->device.mKernel, param)) {
1328 return false;
1329 }
1330 } else if (object->mType == SchemaType::FRAMEWORK) {
1331 #pragma clang diagnostic push
1332 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1333 if (!parseChildren(root, VndkConverter{}, &object->framework.mVndks, param)) {
1334 return false;
1335 }
1336 for (const auto& vndk : object->framework.mVndks) {
1337 if (!vndk.mVersionRange.isSingleVersion()) {
1338 *param.error = "vndk.version " + to_string(vndk.mVersionRange) +
1339 " cannot be a range for manifests";
1340 return false;
1341 }
1342 }
1343 #pragma clang diagnostic pop
1344
1345 if (!parseChildren(root, VendorNdkConverter{}, &object->framework.mVendorNdks, param)) {
1346 return false;
1347 }
1348
1349 std::set<std::string> vendorNdkVersions;
1350 for (const auto& vendorNdk : object->framework.mVendorNdks) {
1351 if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) {
1352 *param.error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version();
1353 return false;
1354 }
1355 vendorNdkVersions.insert(vendorNdk.version());
1356 }
1357
1358 if (!parseOptionalChild(root, SystemSdkConverter{}, {}, &object->framework.mSystemSdk,
1359 param)) {
1360 return false;
1361 }
1362 }
1363 for (auto &&hal : hals) {
1364 std::string description{hal.name};
1365 if (!object->add(std::move(hal), param.error)) {
1366 param.error->insert(0, "Duplicated manifest.hal entry " + description + ": ");
1367 return false;
1368 }
1369 }
1370
1371 std::vector<ManifestXmlFile> xmlFiles;
1372 if (!parseChildren(root, ManifestXmlFileConverter{}, &xmlFiles, param)) {
1373 return false;
1374 }
1375 for (auto&& xmlFile : xmlFiles) {
1376 std::string description{xmlFile.name()};
1377 if (!object->addXmlFile(std::move(xmlFile))) {
1378 *param.error = "Duplicated manifest.xmlfile entry " + description +
1379 "; entries cannot have duplicated name and version";
1380 return false;
1381 }
1382 }
1383
1384 return true;
1385 }
1386 };
1387
1388 struct AvbVersionConverter : public XmlTextConverter<Version> {
elementNameandroid::vintf::AvbVersionConverter1389 std::string elementName() const override { return "vbmeta-version"; }
1390 };
1391
1392 struct AvbConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::AvbConverter1393 std::string elementName() const override { return "avb"; }
mutateNodeandroid::vintf::AvbConverter1394 void mutateNode(const Version& object, NodeType* root,
1395 const MutateNodeParam& param) const override {
1396 appendChild(root, AvbVersionConverter{}(object, param));
1397 }
buildObjectandroid::vintf::AvbConverter1398 bool buildObject(Version* object, NodeType* root,
1399 const BuildObjectParam& param) const override {
1400 return parseChild(root, AvbVersionConverter{}, object, param);
1401 }
1402 };
1403
1404 struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> {
elementNameandroid::vintf::MatrixXmlFileConverter1405 std::string elementName() const override { return "xmlfile"; }
mutateNodeandroid::vintf::MatrixXmlFileConverter1406 void mutateNode(const MatrixXmlFile& object, NodeType* root,
1407 const MutateNodeParam& param) const override {
1408 appendTextElement(root, "name", object.name(), param.d);
1409 appendAttr(root, "format", object.format());
1410 appendAttr(root, "optional", object.optional());
1411 appendChild(root, VersionRangeConverter{}(object.versionRange(), param));
1412 if (!object.overriddenPath().empty()) {
1413 appendTextElement(root, "path", object.overriddenPath(), param.d);
1414 }
1415 }
buildObjectandroid::vintf::MatrixXmlFileConverter1416 bool buildObject(MatrixXmlFile* object, NodeType* root,
1417 const BuildObjectParam& param) const override {
1418 if (!parseTextElement(root, "name", &object->mName, param.error) ||
1419 !parseAttr(root, "format", &object->mFormat, param.error) ||
1420 !parseOptionalAttr(root, "optional", false, &object->mOptional, param.error) ||
1421 !parseChild(root, VersionRangeConverter{}, &object->mVersionRange, param) ||
1422 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, param.error)) {
1423 return false;
1424 }
1425 return true;
1426 }
1427 };
1428
1429 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
elementNameandroid::vintf::CompatibilityMatrixConverter1430 std::string elementName() const override { return "compatibility-matrix"; }
mutateNodeandroid::vintf::CompatibilityMatrixConverter1431 void mutateNode(const CompatibilityMatrix& object, NodeType* root,
1432 const MutateNodeParam& param) const override {
1433 if (param.flags.isMetaVersionEnabled()) {
1434 appendAttr(root, "version", kMetaVersion);
1435 }
1436 if (param.flags.isSchemaTypeEnabled()) {
1437 appendAttr(root, "type", object.mType);
1438 }
1439
1440 if (param.flags.isHalsEnabled()) {
1441 appendChildren(root, MatrixHalConverter{}, iterateValues(object.mHals), param);
1442 }
1443 if (object.mType == SchemaType::FRAMEWORK) {
1444 if (param.flags.isKernelEnabled()) {
1445 appendChildren(root, MatrixKernelConverter{}, object.framework.mKernels, param);
1446 }
1447 if (param.flags.isSepolicyEnabled()) {
1448 if (!(object.framework.mSepolicy == Sepolicy{})) {
1449 appendChild(root, SepolicyConverter{}(object.framework.mSepolicy, param));
1450 }
1451 }
1452 if (param.flags.isAvbEnabled()) {
1453 if (!(object.framework.mAvbMetaVersion == Version{})) {
1454 appendChild(root, AvbConverter{}(object.framework.mAvbMetaVersion, param));
1455 }
1456 }
1457 if (object.mLevel != Level::UNSPECIFIED) {
1458 this->appendAttr(root, "level", object.mLevel);
1459 }
1460 } else if (object.mType == SchemaType::DEVICE) {
1461 if (param.flags.isVndkEnabled()) {
1462 #pragma clang diagnostic push
1463 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1464 if (!(object.device.mVndk == Vndk{})) {
1465 appendChild(root, VndkConverter{}(object.device.mVndk, param));
1466 }
1467 #pragma clang diagnostic pop
1468
1469 if (!(object.device.mVendorNdk == VendorNdk{})) {
1470 appendChild(root, VendorNdkConverter{}(object.device.mVendorNdk, param));
1471 }
1472 }
1473
1474 if (param.flags.isSsdkEnabled()) {
1475 if (!object.device.mSystemSdk.empty()) {
1476 appendChild(root, SystemSdkConverter{}(object.device.mSystemSdk, param));
1477 }
1478 }
1479 }
1480
1481 if (param.flags.isXmlFilesEnabled()) {
1482 appendChildren(root, MatrixXmlFileConverter{}, object.getXmlFiles(), param);
1483 }
1484 }
buildObjectandroid::vintf::CompatibilityMatrixConverter1485 bool buildObject(CompatibilityMatrix* object, NodeType* root,
1486 const BuildObjectParam& constParam) const override {
1487 BuildObjectParam param = constParam;
1488 if (!parseAttr(root, "version", ¶m.metaVersion, param.error)) return false;
1489 if (param.metaVersion > kMetaVersion) {
1490 *param.error = "Unrecognized compatibility-matrix.version " +
1491 to_string(param.metaVersion) + " (libvintf@" + to_string(kMetaVersion) +
1492 ")";
1493 return false;
1494 }
1495
1496 std::vector<MatrixHal> hals;
1497 if (!parseAttr(root, "type", &object->mType, param.error) ||
1498 !parseChildren(root, MatrixHalConverter{}, &hals, param)) {
1499 return false;
1500 }
1501
1502 if (object->mType == SchemaType::FRAMEWORK) {
1503 // <avb> and <sepolicy> can be missing because it can be determined at build time, not
1504 // hard-coded in the XML file.
1505 if (!parseChildren(root, MatrixKernelConverter{}, &object->framework.mKernels, param) ||
1506 !parseOptionalChild(root, SepolicyConverter{}, {}, &object->framework.mSepolicy,
1507 param) ||
1508 !parseOptionalChild(root, AvbConverter{}, {}, &object->framework.mAvbMetaVersion,
1509 param)) {
1510 return false;
1511 }
1512
1513 std::set<Version> seenKernelVersions;
1514 for (const auto& kernel : object->framework.mKernels) {
1515 Version minLts(kernel.minLts().version, kernel.minLts().majorRev);
1516 if (seenKernelVersions.find(minLts) != seenKernelVersions.end()) {
1517 continue;
1518 }
1519 if (!kernel.conditions().empty()) {
1520 *param.error = "First <kernel> for version " + to_string(minLts) +
1521 " must have empty <conditions> for backwards compatibility.";
1522 return false;
1523 }
1524 seenKernelVersions.insert(minLts);
1525 }
1526
1527 if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel,
1528 param.error)) {
1529 return false;
1530 }
1531
1532 } else if (object->mType == SchemaType::DEVICE) {
1533 // <vndk> can be missing because it can be determined at build time, not hard-coded
1534 // in the XML file.
1535 #pragma clang diagnostic push
1536 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1537 if (!parseOptionalChild(root, VndkConverter{}, {}, &object->device.mVndk, param)) {
1538 return false;
1539 }
1540 #pragma clang diagnostic pop
1541
1542 if (!parseOptionalChild(root, VendorNdkConverter{}, {}, &object->device.mVendorNdk,
1543 param)) {
1544 return false;
1545 }
1546
1547 if (!parseOptionalChild(root, SystemSdkConverter{}, {}, &object->device.mSystemSdk,
1548 param)) {
1549 return false;
1550 }
1551 }
1552
1553 for (auto &&hal : hals) {
1554 if (!object->add(std::move(hal))) {
1555 *param.error = "Duplicated compatibility-matrix.hal entry";
1556 return false;
1557 }
1558 }
1559
1560 std::vector<MatrixXmlFile> xmlFiles;
1561 if (!parseChildren(root, MatrixXmlFileConverter{}, &xmlFiles, param)) {
1562 return false;
1563 }
1564 for (auto&& xmlFile : xmlFiles) {
1565 if (!xmlFile.optional()) {
1566 *param.error = "compatibility-matrix.xmlfile entry " + xmlFile.name() +
1567 " has to be optional for compatibility matrix version 1.0";
1568 return false;
1569 }
1570 std::string description{xmlFile.name()};
1571 if (!object->addXmlFile(std::move(xmlFile))) {
1572 *param.error = "Duplicated compatibility-matrix.xmlfile entry " + description;
1573 return false;
1574 }
1575 }
1576
1577 return true;
1578 }
1579 };
1580
1581 #define CREATE_CONVERT_FN(type) \
1582 std::string toXml(const type& o, SerializeFlags::Type flags) { \
1583 return type##Converter{}.toXml(o, flags); \
1584 } \
1585 bool fromXml(type* o, const std::string& xml, std::string* error) { \
1586 return type##Converter{}.fromXml(o, xml, error); \
1587 }
1588
1589 // Create convert functions for public usage.
1590 CREATE_CONVERT_FN(HalManifest)
1591 CREATE_CONVERT_FN(CompatibilityMatrix)
1592
1593 // Create convert functions for internal usage.
1594 CREATE_CONVERT_FN(KernelInfo)
1595
1596 // Create convert functions for testing.
1597 CREATE_CONVERT_FN(Version)
1598 CREATE_CONVERT_FN(SepolicyVersion)
1599 CREATE_CONVERT_FN(KernelConfigTypedValue)
1600 CREATE_CONVERT_FN(MatrixHal)
1601 CREATE_CONVERT_FN(ManifestHal)
1602
1603 #undef CREATE_CONVERT_FN
1604
1605 } // namespace vintf
1606 } // namespace android
1607