summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandroid-build-team Robot2018-02-15 02:23:35 -0600
committerandroid-build-team Robot2018-02-15 02:23:35 -0600
commitf57fb1b2ee6eed3149b4b2efb58c57baa085f0c0 (patch)
treed1fd68449b9b8391e7bc204f5ea549e51f9d5084
parent330b2d71ee774cddfc70ae1c6c1269d04fd4ab38 (diff)
parentdc8bd93571b8a397f46fba1b83a92119391a6c32 (diff)
downloadplatform-system-libvintf-f57fb1b2ee6eed3149b4b2efb58c57baa085f0c0.tar.gz
platform-system-libvintf-f57fb1b2ee6eed3149b4b2efb58c57baa085f0c0.tar.xz
platform-system-libvintf-f57fb1b2ee6eed3149b4b2efb58c57baa085f0c0.zip
Snap for 4605948 from dc8bd93571b8a397f46fba1b83a92119391a6c32 to pi-release
Change-Id: Idcbd948929538742566d58c97a7eafc3c941b28b
-rw-r--r--AssembleVintf.cpp35
-rw-r--r--VintfObject.cpp8
-rw-r--r--check_vintf.cpp4
-rw-r--r--include/vintf/parse_xml.h20
-rw-r--r--parse_xml.cpp463
-rw-r--r--test/LibVintfTest.cpp39
-rw-r--r--utils.h4
7 files changed, 318 insertions, 255 deletions
diff --git a/AssembleVintf.cpp b/AssembleVintf.cpp
index 96e8537..39bdd3a 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -337,9 +337,9 @@ class AssembleVintfImpl : public AssembleVintf {
337 337
338 if (mCheckFile != nullptr) { 338 if (mCheckFile != nullptr) {
339 CompatibilityMatrix checkMatrix; 339 CompatibilityMatrix checkMatrix;
340 if (!gCompatibilityMatrixConverter(&checkMatrix, read(*mCheckFile))) { 340 if (!gCompatibilityMatrixConverter(&checkMatrix, read(*mCheckFile), &error)) {
341 std::cerr << "Cannot parse check file as a compatibility matrix: " 341 std::cerr << "Cannot parse check file as a compatibility matrix: " << error
342 << gCompatibilityMatrixConverter.lastError() << std::endl; 342 << std::endl;
343 return false; 343 return false;
344 } 344 }
345 if (!halManifest->checkCompatibility(checkMatrix, &error)) { 345 if (!halManifest->checkCompatibility(checkMatrix, &error)) {
@@ -443,9 +443,9 @@ class AssembleVintfImpl : public AssembleVintf {
443 Level deviceLevel = Level::UNSPECIFIED; 443 Level deviceLevel = Level::UNSPECIFIED;
444 if (mCheckFile != nullptr) { 444 if (mCheckFile != nullptr) {
445 checkManifest = std::make_unique<HalManifest>(); 445 checkManifest = std::make_unique<HalManifest>();
446 if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile))) { 446 if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile), &error)) {
447 std::cerr << "Cannot parse check file as a HAL manifest: " 447 std::cerr << "Cannot parse check file as a HAL manifest: " << error
448 << gHalManifestConverter.lastError() << std::endl; 448 << std::endl;
449 return false; 449 return false;
450 } 450 }
451 deviceLevel = checkManifest->level(); 451 deviceLevel = checkManifest->level();
@@ -525,10 +525,10 @@ class AssembleVintfImpl : public AssembleVintf {
525 enum AssembleStatus { SUCCESS, FAIL_AND_EXIT, TRY_NEXT }; 525 enum AssembleStatus { SUCCESS, FAIL_AND_EXIT, TRY_NEXT };
526 template <typename Schema, typename AssembleFunc> 526 template <typename Schema, typename AssembleFunc>
527 AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName, 527 AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName,
528 AssembleFunc assemble) { 528 AssembleFunc assemble, std::string* error) {
529 Schemas<Schema> schemas; 529 Schemas<Schema> schemas;
530 Schema schema; 530 Schema schema;
531 if (!converter(&schema, read(mInFiles.front().stream()))) { 531 if (!converter(&schema, read(mInFiles.front().stream()), error)) {
532 return TRY_NEXT; 532 return TRY_NEXT;
533 } 533 }
534 auto firstType = schema.type(); 534 auto firstType = schema.type();
@@ -537,10 +537,10 @@ class AssembleVintfImpl : public AssembleVintf {
537 for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) { 537 for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) {
538 Schema additionalSchema; 538 Schema additionalSchema;
539 const std::string& fileName = it->name(); 539 const std::string& fileName = it->name();
540 if (!converter(&additionalSchema, read(it->stream()))) { 540 if (!converter(&additionalSchema, read(it->stream()), error)) {
541 std::cerr << "File \"" << fileName << "\" is not a valid " << firstType << " " 541 std::cerr << "File \"" << fileName << "\" is not a valid " << firstType << " "
542 << schemaName << " (but the first file is a valid " << firstType << " " 542 << schemaName << " (but the first file is a valid " << firstType << " "
543 << schemaName << "). Error: " << converter.lastError() << std::endl; 543 << schemaName << "). Error: " << *error << std::endl;
544 return FAIL_AND_EXIT; 544 return FAIL_AND_EXIT;
545 } 545 }
546 if (additionalSchema.type() != firstType) { 546 if (additionalSchema.type() != firstType) {
@@ -562,23 +562,26 @@ class AssembleVintfImpl : public AssembleVintf {
562 return false; 562 return false;
563 } 563 }
564 564
565 std::string manifestError;
565 auto status = tryAssemble(gHalManifestConverter, "manifest", 566 auto status = tryAssemble(gHalManifestConverter, "manifest",
566 std::bind(&AssembleVintfImpl::assembleHalManifest, this, _1)); 567 std::bind(&AssembleVintfImpl::assembleHalManifest, this, _1),
568 &manifestError);
567 if (status == SUCCESS) return true; 569 if (status == SUCCESS) return true;
568 if (status == FAIL_AND_EXIT) return false; 570 if (status == FAIL_AND_EXIT) return false;
569 571
570 resetInFiles(); 572 resetInFiles();
571 573
574 std::string matrixError;
572 status = tryAssemble(gCompatibilityMatrixConverter, "compatibility matrix", 575 status = tryAssemble(gCompatibilityMatrixConverter, "compatibility matrix",
573 std::bind(&AssembleVintfImpl::assembleCompatibilityMatrix, this, _1)); 576 std::bind(&AssembleVintfImpl::assembleCompatibilityMatrix, this, _1),
577 &matrixError);
574 if (status == SUCCESS) return true; 578 if (status == SUCCESS) return true;
575 if (status == FAIL_AND_EXIT) return false; 579 if (status == FAIL_AND_EXIT) return false;
576 580
577 std::cerr << "Input file has unknown format." << std::endl 581 std::cerr << "Input file has unknown format." << std::endl
578 << "Error when attempting to convert to manifest: " 582 << "Error when attempting to convert to manifest: " << manifestError << std::endl
579 << gHalManifestConverter.lastError() << std::endl 583 << "Error when attempting to convert to compatibility matrix: " << matrixError
580 << "Error when attempting to convert to compatibility matrix: " 584 << std::endl;
581 << gCompatibilityMatrixConverter.lastError() << std::endl;
582 return false; 585 return false;
583 } 586 }
584 587
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 3f097f7..e89ca56 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -295,11 +295,9 @@ std::vector<Named<CompatibilityMatrix>> VintfObject::GetAllFrameworkMatrixLevels
295 } 295 }
296 296
297 auto it = results.emplace(results.end()); 297 auto it = results.emplace(results.end());
298 if (!gCompatibilityMatrixConverter(&it->object, content)) { 298 if (!gCompatibilityMatrixConverter(&it->object, content, error)) {
299 if (error) { 299 if (error) {
300 // TODO(b/71874788): do not use lastError() because it is not thread-safe. 300 *error += "Ignore file " + path + ": " + *error + "\n";
301 *error +=
302 "Ignore file " + path + ": " + gCompatibilityMatrixConverter.lastError() + "\n";
303 } 301 }
304 results.erase(it); 302 results.erase(it);
305 continue; 303 continue;
@@ -368,7 +366,7 @@ template<typename T>
368static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse, 366static ParseStatus tryParse(const std::string &xml, const XmlConverter<T> &parse,
369 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) { 367 std::shared_ptr<T> *fwk, std::shared_ptr<T> *dev) {
370 std::shared_ptr<T> ret = std::make_shared<T>(); 368 std::shared_ptr<T> ret = std::make_shared<T>();
371 if (!parse(ret.get(), xml)) { 369 if (!parse(ret.get(), xml, nullptr /* error */)) {
372 return ParseStatus::PARSE_ERROR; 370 return ParseStatus::PARSE_ERROR;
373 } 371 }
374 if (ret->type() == SchemaType::FRAMEWORK) { 372 if (ret->type() == SchemaType::FRAMEWORK) {
diff --git a/check_vintf.cpp b/check_vintf.cpp
index 67ecd4e..f64f81d 100644
--- a/check_vintf.cpp
+++ b/check_vintf.cpp
@@ -33,8 +33,8 @@ std::unique_ptr<T> readObject(const std::string& path, const XmlConverter<T>& co
33 return nullptr; 33 return nullptr;
34 } 34 }
35 auto ret = std::make_unique<T>(); 35 auto ret = std::make_unique<T>();
36 if (!converter(ret.get(), xml)) { 36 if (!converter(ret.get(), xml, &error)) {
37 std::cerr << "Error: Cannot parse '" << path << "': " << converter.lastError() << std::endl; 37 std::cerr << "Error: Cannot parse '" << path << "': " << error << std::endl;
38 return nullptr; 38 return nullptr;
39 } 39 }
40 return ret; 40 return ret;
diff --git a/include/vintf/parse_xml.h b/include/vintf/parse_xml.h
index 314fb72..59db3bf 100644
--- a/include/vintf/parse_xml.h
+++ b/include/vintf/parse_xml.h
@@ -42,16 +42,28 @@ template<typename Object>
42struct XmlConverter { 42struct XmlConverter {
43 XmlConverter() {} 43 XmlConverter() {}
44 virtual ~XmlConverter() {} 44 virtual ~XmlConverter() {}
45
45 virtual const std::string &lastError() const = 0; 46 virtual const std::string &lastError() const = 0;
47
48 // deprecated. Use operator() instead.
46 virtual std::string serialize(const Object& o, SerializeFlags flags = EVERYTHING) const = 0; 49 virtual std::string serialize(const Object& o, SerializeFlags flags = EVERYTHING) const = 0;
47 virtual bool deserialize(Object *o, const std::string &xml) const = 0; 50
51 // Serialize an object to XML.
48 virtual std::string operator()(const Object& o, SerializeFlags flags = EVERYTHING) const = 0; 52 virtual std::string operator()(const Object& o, SerializeFlags flags = EVERYTHING) const = 0;
49 virtual bool operator()(Object *o, const std::string &xml) const = 0; 53
54 // deprecated. Use operator() instead. These APIs sets lastError(). Kept for testing.
55 virtual bool deserialize(Object* o, const std::string& xml) = 0;
56 virtual bool operator()(Object* o, const std::string& xml) = 0;
57
58 // Deserialize an XML to object. Return whether it is successful. This API
59 // does not touch lastError(), but instead sets error message
60 // to optional "error" out parameter (which can be null).
61 virtual bool operator()(Object* o, const std::string& xml, std::string* error) const = 0;
50}; 62};
51 63
52extern const XmlConverter<HalManifest> &gHalManifestConverter; 64extern XmlConverter<HalManifest>& gHalManifestConverter;
53 65
54extern const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter; 66extern XmlConverter<CompatibilityMatrix>& gCompatibilityMatrixConverter;
55 67
56} // namespace vintf 68} // namespace vintf
57} // namespace android 69} // namespace android
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 7abbc55..bca26e1 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -143,50 +143,59 @@ struct XmlNodeConverter : public XmlConverter<Object> {
143 virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags) const { 143 virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags) const {
144 mutateNode(o, n, d); 144 mutateNode(o, n, d);
145 } 145 }
146 virtual bool buildObject(Object *o, NodeType *n) const = 0; 146 virtual bool buildObject(Object* o, NodeType* n, std::string* error) const = 0;
147 virtual std::string elementName() const = 0; 147 virtual std::string elementName() const = 0;
148 148
149 // convenience methods for user 149 // convenience methods for user
150 inline const std::string &lastError() const { return mLastError; } 150 inline const std::string& lastError() const override { return mLastError; }
151 inline NodeType* serialize(const Object& o, DocType* d, 151 inline NodeType* serialize(const Object& o, DocType* d,
152 SerializeFlags flags = EVERYTHING) const { 152 SerializeFlags flags = EVERYTHING) const {
153 NodeType *root = createNode(this->elementName(), d); 153 NodeType *root = createNode(this->elementName(), d);
154 this->mutateNode(o, root, d, flags); 154 this->mutateNode(o, root, d, flags);
155 return root; 155 return root;
156 } 156 }
157 inline std::string serialize(const Object& o, SerializeFlags flags) const { 157 inline std::string serialize(const Object& o, SerializeFlags flags) const override {
158 DocType *doc = createDocument(); 158 DocType *doc = createDocument();
159 appendChild(doc, serialize(o, doc, flags)); 159 appendChild(doc, serialize(o, doc, flags));
160 std::string s = printDocument(doc); 160 std::string s = printDocument(doc);
161 deleteDocument(doc); 161 deleteDocument(doc);
162 return s; 162 return s;
163 } 163 }
164 inline bool deserialize(Object *object, NodeType *root) const { 164 inline bool deserialize(Object* object, NodeType* root) {
165 bool ret = deserialize(object, root, &mLastError);
166 return ret;
167 }
168 inline bool deserialize(Object* o, const std::string& xml) override {
169 bool ret = (*this)(o, xml, &mLastError);
170 return ret;
171 }
172 inline bool deserialize(Object* object, NodeType* root, std::string* error) const {
165 if (nameOf(root) != this->elementName()) { 173 if (nameOf(root) != this->elementName()) {
166 return false; 174 return false;
167 } 175 }
168 return this->buildObject(object, root); 176 return this->buildObject(object, root, error);
169 } 177 }
170 inline bool deserialize(Object *o, const std::string &xml) const { 178 inline bool operator()(Object* o, const std::string& xml, std::string* error) const override {
171 DocType *doc = createDocument(xml); 179 std::string errorBuffer;
180 if (error == nullptr) error = &errorBuffer;
181
182 auto doc = createDocument(xml);
172 if (doc == nullptr) { 183 if (doc == nullptr) {
173 this->mLastError = "Not a valid XML"; 184 *error = "Not a valid XML";
174 return false; 185 return false;
175 } 186 }
176 bool ret = deserialize(o, getRootChild(doc)); 187 bool ret = deserialize(o, getRootChild(doc), error);
177 deleteDocument(doc); 188 deleteDocument(doc);
178 return ret; 189 return ret;
179 } 190 }
180 inline NodeType *operator()(const Object &o, DocType *d) const { 191 inline NodeType *operator()(const Object &o, DocType *d) const {
181 return serialize(o, d); 192 return serialize(o, d);
182 } 193 }
183 inline std::string operator()(const Object& o, SerializeFlags flags) const { 194 inline std::string operator()(const Object& o, SerializeFlags flags) const override {
184 return serialize(o, flags); 195 return serialize(o, flags);
185 } 196 }
186 inline bool operator()(Object *o, NodeType *node) const { 197 inline bool operator()(Object* o, NodeType* node) { return deserialize(o, node); }
187 return deserialize(o, node); 198 inline bool operator()(Object* o, const std::string& xml) override {
188 }
189 inline bool operator()(Object *o, const std::string &xml) const {
190 return deserialize(o, xml); 199 return deserialize(o, xml);
191 } 200 }
192 201
@@ -230,11 +239,11 @@ struct XmlNodeConverter : public XmlConverter<Object> {
230 } 239 }
231 240
232 // All parse* functions helps buildObject() to deserialize XML to the object. Returns 241 // All parse* functions helps buildObject() to deserialize XML to the object. Returns
233 // true if deserialization is successful, false if any error, and mLastError will be 242 // true if deserialization is successful, false if any error, and "error" will be
234 // set to error message. 243 // set to error message.
235 template <typename T> 244 template <typename T>
236 inline bool parseOptionalAttr(NodeType *root, const std::string &attrName, 245 inline bool parseOptionalAttr(NodeType* root, const std::string& attrName, T&& defaultValue,
237 T &&defaultValue, T *attr) const { 246 T* attr, std::string* /* error */) const {
238 std::string attrText; 247 std::string attrText;
239 bool success = getAttr(root, attrName, &attrText) && 248 bool success = getAttr(root, attrName, &attrText) &&
240 ::android::vintf::parse(attrText, attr); 249 ::android::vintf::parse(attrText, attr);
@@ -245,31 +254,33 @@ struct XmlNodeConverter : public XmlConverter<Object> {
245 } 254 }
246 255
247 template <typename T> 256 template <typename T>
248 inline bool parseAttr(NodeType *root, const std::string &attrName, T *attr) const { 257 inline bool parseAttr(NodeType* root, const std::string& attrName, T* attr,
258 std::string* error) const {
249 std::string attrText; 259 std::string attrText;
250 bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr); 260 bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
251 if (!ret) { 261 if (!ret) {
252 mLastError = "Could not find/parse attr with name \"" + attrName + "\" and value \"" + 262 *error = "Could not find/parse attr with name \"" + attrName + "\" and value \"" +
253 attrText + "\" for element <" + elementName() + ">"; 263 attrText + "\" for element <" + elementName() + ">";
254 } 264 }
255 return ret; 265 return ret;
256 } 266 }
257 267
258 inline bool parseAttr(NodeType *root, const std::string &attrName, std::string *attr) const { 268 inline bool parseAttr(NodeType* root, const std::string& attrName, std::string* attr,
269 std::string* error) const {
259 bool ret = getAttr(root, attrName, attr); 270 bool ret = getAttr(root, attrName, attr);
260 if (!ret) { 271 if (!ret) {
261 mLastError = "Could not find attr with name \"" + attrName + "\" for element <" 272 *error = "Could not find attr with name \"" + attrName + "\" for element <" +
262 + elementName() + ">"; 273 elementName() + ">";
263 } 274 }
264 return ret; 275 return ret;
265 } 276 }
266 277
267 inline bool parseTextElement(NodeType *root, 278 inline bool parseTextElement(NodeType* root, const std::string& elementName, std::string* s,
268 const std::string &elementName, std::string *s) const { 279 std::string* error) const {
269 NodeType *child = getChild(root, elementName); 280 NodeType *child = getChild(root, elementName);
270 if (child == nullptr) { 281 if (child == nullptr) {
271 mLastError = "Could not find element with name <" + elementName + "> in element <" 282 *error = "Could not find element with name <" + elementName + "> in element <" +
272 + this->elementName() + ">"; 283 this->elementName() + ">";
273 return false; 284 return false;
274 } 285 }
275 *s = getText(child); 286 *s = getText(child);
@@ -277,14 +288,15 @@ struct XmlNodeConverter : public XmlConverter<Object> {
277 } 288 }
278 289
279 inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName, 290 inline bool parseOptionalTextElement(NodeType* root, const std::string& elementName,
280 std::string&& defaultValue, std::string* s) const { 291 std::string&& defaultValue, std::string* s,
292 std::string* /* error */) const {
281 NodeType* child = getChild(root, elementName); 293 NodeType* child = getChild(root, elementName);
282 *s = child == nullptr ? std::move(defaultValue) : getText(child); 294 *s = child == nullptr ? std::move(defaultValue) : getText(child);
283 return true; 295 return true;
284 } 296 }
285 297
286 inline bool parseTextElements(NodeType *root, const std::string &elementName, 298 inline bool parseTextElements(NodeType* root, const std::string& elementName,
287 std::vector<std::string> *v) const { 299 std::vector<std::string>* v, std::string* /* error */) const {
288 auto nodes = getChildren(root, elementName); 300 auto nodes = getChildren(root, elementName);
289 v->resize(nodes.size()); 301 v->resize(nodes.size());
290 for (size_t i = 0; i < nodes.size(); ++i) { 302 for (size_t i = 0; i < nodes.size(); ++i) {
@@ -294,43 +306,37 @@ struct XmlNodeConverter : public XmlConverter<Object> {
294 } 306 }
295 307
296 template <typename T> 308 template <typename T>
297 inline bool parseChild(NodeType *root, const XmlNodeConverter<T> &conv, T *t) const { 309 inline bool parseChild(NodeType* root, const XmlNodeConverter<T>& conv, T* t,
310 std::string* error) const {
298 NodeType *child = getChild(root, conv.elementName()); 311 NodeType *child = getChild(root, conv.elementName());
299 if (child == nullptr) { 312 if (child == nullptr) {
300 mLastError = "Could not find element with name <" + conv.elementName() + "> in element <" 313 *error = "Could not find element with name <" + conv.elementName() + "> in element <" +
301 + this->elementName() + ">"; 314 this->elementName() + ">";
302 return false; 315 return false;
303 } 316 }
304 bool success = conv.deserialize(t, child); 317 return conv.deserialize(t, child, error);
305 if (!success) {
306 mLastError = conv.lastError();
307 }
308 return success;
309 } 318 }
310 319
311 template <typename T> 320 template <typename T>
312 inline bool parseOptionalChild(NodeType *root, const XmlNodeConverter<T> &conv, 321 inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
313 T &&defaultValue, T *t) const { 322 T&& defaultValue, T* t, std::string* error) const {
314 NodeType *child = getChild(root, conv.elementName()); 323 NodeType *child = getChild(root, conv.elementName());
315 if (child == nullptr) { 324 if (child == nullptr) {
316 *t = std::move(defaultValue); 325 *t = std::move(defaultValue);
317 return true; 326 return true;
318 } 327 }
319 bool success = conv.deserialize(t, child); 328 return conv.deserialize(t, child, error);
320 if (!success) {
321 mLastError = conv.lastError();
322 }
323 return success;
324 } 329 }
325 330
326 template <typename T> 331 template <typename T>
327 inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::vector<T> *v) const { 332 inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v,
333 std::string* error) const {
328 auto nodes = getChildren(root, conv.elementName()); 334 auto nodes = getChildren(root, conv.elementName());
329 v->resize(nodes.size()); 335 v->resize(nodes.size());
330 for (size_t i = 0; i < nodes.size(); ++i) { 336 for (size_t i = 0; i < nodes.size(); ++i) {
331 if (!conv.deserialize(&v->at(i), nodes[i])) { 337 if (!conv.deserialize(&v->at(i), nodes[i], error)) {
332 mLastError = "Could not parse element with name <" + conv.elementName() 338 *error = "Could not parse element with name <" + conv.elementName() +
333 + "> in element <" + this->elementName() + ">: " + conv.lastError(); 339 "> in element <" + this->elementName() + ">: " + *error;
334 return false; 340 return false;
335 } 341 }
336 } 342 }
@@ -338,37 +344,39 @@ struct XmlNodeConverter : public XmlConverter<Object> {
338 } 344 }
339 345
340 template <typename T> 346 template <typename T>
341 inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::set<T> *s) const { 347 inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::set<T>* s,
348 std::string* error) const {
342 std::vector<T> vec; 349 std::vector<T> vec;
343 if (!parseChildren(root, conv, &vec)) { 350 if (!parseChildren(root, conv, &vec, error)) {
344 return false; 351 return false;
345 } 352 }
346 s->clear(); 353 s->clear();
347 s->insert(vec.begin(), vec.end()); 354 s->insert(vec.begin(), vec.end());
348 if (s->size() != vec.size()) { 355 if (s->size() != vec.size()) {
349 mLastError = "Duplicated elements <" + conv.elementName() + "> in element <" 356 *error = "Duplicated elements <" + conv.elementName() + "> in element <" +
350 + this->elementName() + ">"; 357 this->elementName() + ">";
351 s->clear(); 358 s->clear();
352 return false; 359 return false;
353 } 360 }
354 return true; 361 return true;
355 } 362 }
356 363
357 inline bool parseText(NodeType *node, std::string *s) const { 364 inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const {
358 *s = getText(node); 365 *s = getText(node);
359 return true; 366 return true;
360 } 367 }
361 368
362 template <typename T> 369 template <typename T>
363 inline bool parseText(NodeType *node, T *s) const { 370 inline bool parseText(NodeType* node, T* s, std::string* error) const {
364 std::string text = getText(node); 371 std::string text = getText(node);
365 bool ret = ::android::vintf::parse(text, s); 372 bool ret = ::android::vintf::parse(text, s);
366 if (!ret) { 373 if (!ret) {
367 mLastError = "Could not parse text \"" + text + "\" in element <" + elementName() + ">"; 374 *error = "Could not parse text \"" + text + "\" in element <" + elementName() + ">";
368 } 375 }
369 return ret; 376 return ret;
370 } 377 }
371protected: 378
379 private:
372 mutable std::string mLastError; 380 mutable std::string mLastError;
373}; 381};
374 382
@@ -380,8 +388,8 @@ struct XmlTextConverter : public XmlNodeConverter<Object> {
380 virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override { 388 virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override {
381 appendText(root, ::android::vintf::to_string(object), d); 389 appendText(root, ::android::vintf::to_string(object), d);
382 } 390 }
383 virtual bool buildObject(Object *object, NodeType *root) const override { 391 virtual bool buildObject(Object* object, NodeType* root, std::string* error) const override {
384 return this->parseText(root, object); 392 return this->parseText(root, object, error);
385 } 393 }
386 virtual std::string elementName() const { return mElementName; }; 394 virtual std::string elementName() const { return mElementName; };
387private: 395private:
@@ -390,11 +398,11 @@ private:
390 398
391// ---------------------- XmlNodeConverter definitions end 399// ---------------------- XmlNodeConverter definitions end
392 400
393const XmlTextConverter<Version> versionConverter{"version"}; 401XmlTextConverter<Version> versionConverter{"version"};
394 402
395const XmlTextConverter<VersionRange> versionRangeConverter{"version"}; 403XmlTextConverter<VersionRange> versionRangeConverter{"version"};
396 404
397const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"}; 405XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
398 406
399struct TransportArchConverter : public XmlNodeConverter<TransportArch> { 407struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
400 std::string elementName() const override { return "transport"; } 408 std::string elementName() const override { return "transport"; }
@@ -404,22 +412,22 @@ struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
404 } 412 }
405 appendText(root, ::android::vintf::to_string(object.transport), d); 413 appendText(root, ::android::vintf::to_string(object.transport), d);
406 } 414 }
407 bool buildObject(TransportArch *object, NodeType *root) const override { 415 bool buildObject(TransportArch* object, NodeType* root, std::string* error) const override {
408 if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch) || 416 if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, error) ||
409 !parseText(root, &object->transport)) { 417 !parseText(root, &object->transport, error)) {
410 return false; 418 return false;
411 } 419 }
412 if (!object->isValid()) { 420 if (!object->isValid()) {
413 this->mLastError = "transport == " + ::android::vintf::to_string(object->transport) + 421 *error = "transport == " + ::android::vintf::to_string(object->transport) +
414 " and arch == " + ::android::vintf::to_string(object->arch) + 422 " and arch == " + ::android::vintf::to_string(object->arch) +
415 " is not a valid combination."; 423 " is not a valid combination.";
416 return false; 424 return false;
417 } 425 }
418 return true; 426 return true;
419 } 427 }
420}; 428};
421 429
422const TransportArchConverter transportArchConverter{}; 430TransportArchConverter transportArchConverter{};
423 431
424struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> { 432struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
425 std::string elementName() const override { return "value"; } 433 std::string elementName() const override { return "value"; }
@@ -427,21 +435,22 @@ struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTyp
427 appendAttr(root, "type", object.mType); 435 appendAttr(root, "type", object.mType);
428 appendText(root, ::android::vintf::to_string(object), d); 436 appendText(root, ::android::vintf::to_string(object), d);
429 } 437 }
430 bool buildObject(KernelConfigTypedValue *object, NodeType *root) const override { 438 bool buildObject(KernelConfigTypedValue* object, NodeType* root,
439 std::string* error) const override {
431 std::string stringValue; 440 std::string stringValue;
432 if (!parseAttr(root, "type", &object->mType) || 441 if (!parseAttr(root, "type", &object->mType, error) ||
433 !parseText(root, &stringValue)) { 442 !parseText(root, &stringValue, error)) {
434 return false; 443 return false;
435 } 444 }
436 if (!::android::vintf::parseKernelConfigValue(stringValue, object)) { 445 if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
437 this->mLastError = "Could not parse kernel config value \"" + stringValue + "\""; 446 *error = "Could not parse kernel config value \"" + stringValue + "\"";
438 return false; 447 return false;
439 } 448 }
440 return true; 449 return true;
441 } 450 }
442}; 451};
443 452
444const KernelConfigTypedValueConverter kernelConfigTypedValueConverter{}; 453KernelConfigTypedValueConverter kernelConfigTypedValueConverter{};
445 454
446struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> { 455struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
447 std::string elementName() const override { return "config"; } 456 std::string elementName() const override { return "config"; }
@@ -449,16 +458,16 @@ struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
449 appendChild(root, kernelConfigKeyConverter(object.first, d)); 458 appendChild(root, kernelConfigKeyConverter(object.first, d));
450 appendChild(root, kernelConfigTypedValueConverter(object.second, d)); 459 appendChild(root, kernelConfigTypedValueConverter(object.second, d));
451 } 460 }
452 bool buildObject(KernelConfig *object, NodeType *root) const override { 461 bool buildObject(KernelConfig* object, NodeType* root, std::string* error) const override {
453 if ( !parseChild(root, kernelConfigKeyConverter, &object->first) 462 if (!parseChild(root, kernelConfigKeyConverter, &object->first, error) ||
454 || !parseChild(root, kernelConfigTypedValueConverter, &object->second)) { 463 !parseChild(root, kernelConfigTypedValueConverter, &object->second, error)) {
455 return false; 464 return false;
456 } 465 }
457 return true; 466 return true;
458 } 467 }
459}; 468};
460 469
461const KernelConfigConverter kernelConfigConverter{}; 470KernelConfigConverter kernelConfigConverter{};
462 471
463struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> { 472struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
464 std::string elementName() const override { return "interface"; } 473 std::string elementName() const override { return "interface"; }
@@ -466,23 +475,23 @@ struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
466 appendTextElement(root, "name", intf.name, d); 475 appendTextElement(root, "name", intf.name, d);
467 appendTextElements(root, "instance", intf.instances, d); 476 appendTextElements(root, "instance", intf.instances, d);
468 } 477 }
469 bool buildObject(HalInterface *intf, NodeType *root) const override { 478 bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override {
470 std::vector<std::string> instances; 479 std::vector<std::string> instances;
471 if (!parseTextElement(root, "name", &intf->name) || 480 if (!parseTextElement(root, "name", &intf->name, error) ||
472 !parseTextElements(root, "instance", &instances)) { 481 !parseTextElements(root, "instance", &instances, error)) {
473 return false; 482 return false;
474 } 483 }
475 intf->instances.clear(); 484 intf->instances.clear();
476 intf->instances.insert(instances.begin(), instances.end()); 485 intf->instances.insert(instances.begin(), instances.end());
477 if (intf->instances.size() != instances.size()) { 486 if (intf->instances.size() != instances.size()) {
478 this->mLastError = "Duplicated instances in " + intf->name; 487 *error = "Duplicated instances in " + intf->name;
479 return false; 488 return false;
480 } 489 }
481 return true; 490 return true;
482 } 491 }
483}; 492};
484 493
485const HalInterfaceConverter halInterfaceConverter{}; 494HalInterfaceConverter halInterfaceConverter{};
486 495
487struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> { 496struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
488 std::string elementName() const override { return "hal"; } 497 std::string elementName() const override { return "hal"; }
@@ -493,28 +502,29 @@ struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
493 appendChildren(root, versionRangeConverter, hal.versionRanges, d); 502 appendChildren(root, versionRangeConverter, hal.versionRanges, d);
494 appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d); 503 appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d);
495 } 504 }
496 bool buildObject(MatrixHal *object, NodeType *root) const override { 505 bool buildObject(MatrixHal* object, NodeType* root, std::string* error) const override {
497 std::vector<HalInterface> interfaces; 506 std::vector<HalInterface> interfaces;
498 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) || 507 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) ||
499 !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional) || 508 !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional,
500 !parseTextElement(root, "name", &object->name) || 509 error) ||
501 !parseChildren(root, versionRangeConverter, &object->versionRanges) || 510 !parseTextElement(root, "name", &object->name, error) ||
502 !parseChildren(root, halInterfaceConverter, &interfaces)) { 511 !parseChildren(root, versionRangeConverter, &object->versionRanges, error) ||
512 !parseChildren(root, halInterfaceConverter, &interfaces, error)) {
503 return false; 513 return false;
504 } 514 }
505 for (auto&& interface : interfaces) { 515 for (auto&& interface : interfaces) {
506 std::string name{interface.name}; 516 std::string name{interface.name};
507 auto res = object->interfaces.emplace(std::move(name), std::move(interface)); 517 auto res = object->interfaces.emplace(std::move(name), std::move(interface));
508 if (!res.second) { 518 if (!res.second) {
509 this->mLastError = "Duplicated interface entry \"" + res.first->first + 519 *error = "Duplicated interface entry \"" + res.first->first +
510 "\"; if additional instances are needed, add them to the " 520 "\"; if additional instances are needed, add them to the "
511 "existing <interface> node."; 521 "existing <interface> node.";
512 return false; 522 return false;
513 } 523 }
514 } 524 }
515// Do not check for target-side libvintf to avoid restricting ability for upgrade accidentally. 525// Do not check for target-side libvintf to avoid restricting ability for upgrade accidentally.
516#ifndef LIBVINTF_TARGET 526#ifndef LIBVINTF_TARGET
517 if (!checkAdditionalRestrictionsOnHal(*object)) { 527 if (!checkAdditionalRestrictionsOnHal(*object, error)) {
518 return false; 528 return false;
519 } 529 }
520#endif 530#endif
@@ -523,24 +533,24 @@ struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
523 533
524#ifndef LIBVINTF_TARGET 534#ifndef LIBVINTF_TARGET
525 private: 535 private:
526 bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal) const { 536 bool checkAdditionalRestrictionsOnHal(const MatrixHal& hal, std::string* error) const {
527 if (hal.getName() == "netutils-wrapper") { 537 if (hal.getName() == "netutils-wrapper") {
528 if (hal.versionRanges.size() != 1) { 538 if (hal.versionRanges.size() != 1) {
529 this->mLastError = 539 *error =
530 "netutils-wrapper HAL must specify exactly one version x.0, " 540 "netutils-wrapper HAL must specify exactly one version x.0, "
531 "but multiple <version> element is specified."; 541 "but multiple <version> element is specified.";
532 return false; 542 return false;
533 } 543 }
534 const VersionRange& v = hal.versionRanges.at(0); 544 const VersionRange& v = hal.versionRanges.at(0);
535 if (!v.isSingleVersion()) { 545 if (!v.isSingleVersion()) {
536 this->mLastError = 546 *error =
537 "netutils-wrapper HAL must specify exactly one version x.0, " 547 "netutils-wrapper HAL must specify exactly one version x.0, "
538 "but a range is provided. Perhaps you mean '" + 548 "but a range is provided. Perhaps you mean '" +
539 to_string(Version{v.majorVer, 0}) + "'?"; 549 to_string(Version{v.majorVer, 0}) + "'?";
540 return false; 550 return false;
541 } 551 }
542 if (v.minMinor != 0) { 552 if (v.minMinor != 0) {
543 this->mLastError = 553 *error =
544 "netutils-wrapper HAL must specify exactly one version x.0, " 554 "netutils-wrapper HAL must specify exactly one version x.0, "
545 "but minor version is not 0. Perhaps you mean '" + 555 "but minor version is not 0. Perhaps you mean '" +
546 to_string(Version{v.majorVer, 0}) + "'?"; 556 to_string(Version{v.majorVer, 0}) + "'?";
@@ -552,7 +562,7 @@ struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
552#endif 562#endif
553}; 563};
554 564
555const MatrixHalConverter matrixHalConverter{}; 565MatrixHalConverter matrixHalConverter{};
556 566
557struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> { 567struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> {
558 std::string elementName() const override { return "conditions"; } 568 std::string elementName() const override { return "conditions"; }
@@ -560,12 +570,13 @@ struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<Ker
560 DocType* d) const override { 570 DocType* d) const override {
561 appendChildren(root, kernelConfigConverter, conds, d); 571 appendChildren(root, kernelConfigConverter, conds, d);
562 } 572 }
563 bool buildObject(std::vector<KernelConfig>* object, NodeType* root) const override { 573 bool buildObject(std::vector<KernelConfig>* object, NodeType* root,
564 return parseChildren(root, kernelConfigConverter, object); 574 std::string* error) const override {
575 return parseChildren(root, kernelConfigConverter, object, error);
565 } 576 }
566}; 577};
567 578
568const MatrixKernelConditionsConverter matrixKernelConditionsConverter{}; 579MatrixKernelConditionsConverter matrixKernelConditionsConverter{};
569 580
570struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> { 581struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
571 std::string elementName() const override { return "kernel"; } 582 std::string elementName() const override { return "kernel"; }
@@ -576,17 +587,18 @@ struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
576 } 587 }
577 appendChildren(root, kernelConfigConverter, kernel.mConfigs, d); 588 appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
578 } 589 }
579 bool buildObject(MatrixKernel *object, NodeType *root) const override { 590 bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override {
580 if (!parseAttr(root, "version", &object->mMinLts) || 591 if (!parseAttr(root, "version", &object->mMinLts, error) ||
581 !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions) || 592 !parseOptionalChild(root, matrixKernelConditionsConverter, {}, &object->mConditions,
582 !parseChildren(root, kernelConfigConverter, &object->mConfigs)) { 593 error) ||
594 !parseChildren(root, kernelConfigConverter, &object->mConfigs, error)) {
583 return false; 595 return false;
584 } 596 }
585 return true; 597 return true;
586 } 598 }
587}; 599};
588 600
589const MatrixKernelConverter matrixKernelConverter{}; 601MatrixKernelConverter matrixKernelConverter{};
590 602
591struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> { 603struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
592 std::string elementName() const override { return "hal"; } 604 std::string elementName() const override { return "hal"; }
@@ -600,28 +612,27 @@ struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
600 appendAttr(root, "override", hal.isOverride); 612 appendAttr(root, "override", hal.isOverride);
601 } 613 }
602 } 614 }
603 bool buildObject(ManifestHal *object, NodeType *root) const override { 615 bool buildObject(ManifestHal* object, NodeType* root, std::string* error) const override {
604 std::vector<HalInterface> interfaces; 616 std::vector<HalInterface> interfaces;
605 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) || 617 if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) ||
606 !parseOptionalAttr(root, "override", false, &object->isOverride) || 618 !parseOptionalAttr(root, "override", false, &object->isOverride, error) ||
607 !parseTextElement(root, "name", &object->name) || 619 !parseTextElement(root, "name", &object->name, error) ||
608 !parseOptionalChild(root, transportArchConverter, {}, &object->transportArch) || 620 !parseOptionalChild(root, transportArchConverter, {}, &object->transportArch, error) ||
609 !parseChildren(root, versionConverter, &object->versions) || 621 !parseChildren(root, versionConverter, &object->versions, error) ||
610 !parseChildren(root, halInterfaceConverter, &interfaces)) { 622 !parseChildren(root, halInterfaceConverter, &interfaces, error)) {
611 return false; 623 return false;
612 } 624 }
613 625
614 switch (object->format) { 626 switch (object->format) {
615 case HalFormat::HIDL: { 627 case HalFormat::HIDL: {
616 if (object->transportArch.empty()) { 628 if (object->transportArch.empty()) {
617 this->mLastError = 629 *error = "HIDL HAL '" + object->name + "' should have <transport> defined.";
618 "HIDL HAL '" + object->name + "' should have <transport> defined.";
619 return false; 630 return false;
620 } 631 }
621 } break; 632 } break;
622 case HalFormat::NATIVE: { 633 case HalFormat::NATIVE: {
623 if (!object->transportArch.empty()) { 634 if (!object->transportArch.empty()) {
624 this->mLastError = 635 *error =
625 "Native HAL '" + object->name + "' should not have <transport> defined."; 636 "Native HAL '" + object->name + "' should not have <transport> defined.";
626 return false; 637 return false;
627 } 638 }
@@ -639,19 +650,19 @@ struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
639 auto res = object->interfaces.emplace(interface.name, 650 auto res = object->interfaces.emplace(interface.name,
640 std::move(interface)); 651 std::move(interface));
641 if (!res.second) { 652 if (!res.second) {
642 this->mLastError = "Duplicated interface entry \"" + res.first->first + 653 *error = "Duplicated interface entry \"" + res.first->first +
643 "\"; if additional instances are needed, add them to the " 654 "\"; if additional instances are needed, add them to the "
644 "existing <interface> node."; 655 "existing <interface> node.";
645 return false; 656 return false;
646 } 657 }
647 } 658 }
648 if (!object->isValid()) { 659 if (!object->isValid()) {
649 this->mLastError = "'" + object->name + "' is not a valid Manifest HAL."; 660 *error = "'" + object->name + "' is not a valid Manifest HAL.";
650 return false; 661 return false;
651 } 662 }
652// Do not check for target-side libvintf to avoid restricting upgrade accidentally. 663// Do not check for target-side libvintf to avoid restricting upgrade accidentally.
653#ifndef LIBVINTF_TARGET 664#ifndef LIBVINTF_TARGET
654 if (!checkAdditionalRestrictionsOnHal(*object)) { 665 if (!checkAdditionalRestrictionsOnHal(*object, error)) {
655 return false; 666 return false;
656 } 667 }
657#endif 668#endif
@@ -660,11 +671,11 @@ struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
660 671
661#ifndef LIBVINTF_TARGET 672#ifndef LIBVINTF_TARGET
662 private: 673 private:
663 bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal) const { 674 bool checkAdditionalRestrictionsOnHal(const ManifestHal& hal, std::string* error) const {
664 if (hal.getName() == "netutils-wrapper") { 675 if (hal.getName() == "netutils-wrapper") {
665 for (const Version& v : hal.versions) { 676 for (const Version& v : hal.versions) {
666 if (v.minorVer != 0) { 677 if (v.minorVer != 0) {
667 this->mLastError = 678 *error =
668 "netutils-wrapper HAL must specify exactly one version x.0, " 679 "netutils-wrapper HAL must specify exactly one version x.0, "
669 "but minor version is not 0. Perhaps you mean '" + 680 "but minor version is not 0. Perhaps you mean '" +
670 to_string(Version{v.majorVer, 0}) + "'?"; 681 to_string(Version{v.majorVer, 0}) + "'?";
@@ -679,10 +690,10 @@ struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
679 690
680// Convert ManifestHal from and to XML. Returned object is guaranteed to have 691// Convert ManifestHal from and to XML. Returned object is guaranteed to have
681// .isValid() == true. 692// .isValid() == true.
682const ManifestHalConverter manifestHalConverter{}; 693ManifestHalConverter manifestHalConverter{};
683 694
684const XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"}; 695XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"};
685const XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"}; 696XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"};
686 697
687struct SepolicyConverter : public XmlNodeConverter<Sepolicy> { 698struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
688 std::string elementName() const override { return "sepolicy"; } 699 std::string elementName() const override { return "sepolicy"; }
@@ -690,21 +701,22 @@ struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
690 appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d)); 701 appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d));
691 appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d); 702 appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d);
692 } 703 }
693 bool buildObject(Sepolicy *object, NodeType *root) const override { 704 bool buildObject(Sepolicy* object, NodeType* root, std::string* error) const override {
694 if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion) || 705 if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion,
695 !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges)) { 706 error) ||
707 !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges,
708 error)) {
696 return false; 709 return false;
697 } 710 }
698 return true; 711 return true;
699 } 712 }
700}; 713};
701const SepolicyConverter sepolicyConverter{}; 714SepolicyConverter sepolicyConverter{};
702 715
703[[deprecated]] 716[[deprecated]] XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"};
704const XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"};
705 717
706const XmlTextConverter<std::string> vndkVersionConverter{"version"}; 718XmlTextConverter<std::string> vndkVersionConverter{"version"};
707const XmlTextConverter<std::string> vndkLibraryConverter{"library"}; 719XmlTextConverter<std::string> vndkLibraryConverter{"library"};
708 720
709struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> { 721struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> {
710 std::string elementName() const override { return "vndk"; } 722 std::string elementName() const override { return "vndk"; }
@@ -712,17 +724,16 @@ struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> {
712 appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d)); 724 appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d));
713 appendChildren(root, vndkLibraryConverter, object.mLibraries, d); 725 appendChildren(root, vndkLibraryConverter, object.mLibraries, d);
714 } 726 }
715 bool buildObject(Vndk *object, NodeType *root) const override { 727 bool buildObject(Vndk* object, NodeType* root, std::string* error) const override {
716 if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange) || 728 if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange, error) ||
717 !parseChildren(root, vndkLibraryConverter, &object->mLibraries)) { 729 !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) {
718 return false; 730 return false;
719 } 731 }
720 return true; 732 return true;
721 } 733 }
722}; 734};
723 735
724[[deprecated]] 736[[deprecated]] VndkConverter vndkConverter{};
725const VndkConverter vndkConverter{};
726 737
727struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> { 738struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> {
728 std::string elementName() const override { return "vendor-ndk"; } 739 std::string elementName() const override { return "vendor-ndk"; }
@@ -730,41 +741,41 @@ struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> {
730 appendChild(root, vndkVersionConverter(object.mVersion, d)); 741 appendChild(root, vndkVersionConverter(object.mVersion, d));
731 appendChildren(root, vndkLibraryConverter, object.mLibraries, d); 742 appendChildren(root, vndkLibraryConverter, object.mLibraries, d);
732 } 743 }
733 bool buildObject(VendorNdk* object, NodeType* root) const override { 744 bool buildObject(VendorNdk* object, NodeType* root, std::string* error) const override {
734 if (!parseChild(root, vndkVersionConverter, &object->mVersion) || 745 if (!parseChild(root, vndkVersionConverter, &object->mVersion, error) ||
735 !parseChildren(root, vndkLibraryConverter, &object->mLibraries)) { 746 !parseChildren(root, vndkLibraryConverter, &object->mLibraries, error)) {
736 return false; 747 return false;
737 } 748 }
738 return true; 749 return true;
739 } 750 }
740}; 751};
741 752
742const VendorNdkConverter vendorNdkConverter{}; 753VendorNdkConverter vendorNdkConverter{};
743 754
744const XmlTextConverter<std::string> systemSdkVersionConverter{"version"}; 755XmlTextConverter<std::string> systemSdkVersionConverter{"version"};
745 756
746struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> { 757struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> {
747 std::string elementName() const override { return "system-sdk"; } 758 std::string elementName() const override { return "system-sdk"; }
748 void mutateNode(const SystemSdk& object, NodeType* root, DocType* d) const override { 759 void mutateNode(const SystemSdk& object, NodeType* root, DocType* d) const override {
749 appendChildren(root, systemSdkVersionConverter, object.versions(), d); 760 appendChildren(root, systemSdkVersionConverter, object.versions(), d);
750 } 761 }
751 bool buildObject(SystemSdk* object, NodeType* root) const override { 762 bool buildObject(SystemSdk* object, NodeType* root, std::string* error) const override {
752 return parseChildren(root, systemSdkVersionConverter, &object->mVersions); 763 return parseChildren(root, systemSdkVersionConverter, &object->mVersions, error);
753 } 764 }
754}; 765};
755 766
756const SystemSdkConverter systemSdkConverter{}; 767SystemSdkConverter systemSdkConverter{};
757 768
758struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> { 769struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
759 std::string elementName() const override { return "sepolicy"; } 770 std::string elementName() const override { return "sepolicy"; }
760 void mutateNode(const Version &m, NodeType *root, DocType *d) const override { 771 void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
761 appendChild(root, versionConverter(m, d)); 772 appendChild(root, versionConverter(m, d));
762 } 773 }
763 bool buildObject(Version *object, NodeType *root) const override { 774 bool buildObject(Version* object, NodeType* root, std::string* error) const override {
764 return parseChild(root, versionConverter, object); 775 return parseChild(root, versionConverter, object, error);
765 } 776 }
766}; 777};
767const HalManifestSepolicyConverter halManifestSepolicyConverter{}; 778HalManifestSepolicyConverter halManifestSepolicyConverter{};
768 779
769struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> { 780struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> {
770 std::string elementName() const override { return "xmlfile"; } 781 std::string elementName() const override { return "xmlfile"; }
@@ -775,16 +786,16 @@ struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> {
775 appendTextElement(root, "path", f.overriddenPath(), d); 786 appendTextElement(root, "path", f.overriddenPath(), d);
776 } 787 }
777 } 788 }
778 bool buildObject(ManifestXmlFile* object, NodeType* root) const override { 789 bool buildObject(ManifestXmlFile* object, NodeType* root, std::string* error) const override {
779 if (!parseTextElement(root, "name", &object->mName) || 790 if (!parseTextElement(root, "name", &object->mName, error) ||
780 !parseChild(root, versionConverter, &object->mVersion) || 791 !parseChild(root, versionConverter, &object->mVersion, error) ||
781 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath)) { 792 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) {
782 return false; 793 return false;
783 } 794 }
784 return true; 795 return true;
785 } 796 }
786}; 797};
787const ManifestXmlFileConverter manifestXmlFileConverter{}; 798ManifestXmlFileConverter manifestXmlFileConverter{};
788 799
789struct HalManifestConverter : public XmlNodeConverter<HalManifest> { 800struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
790 std::string elementName() const override { return "manifest"; } 801 std::string elementName() const override { return "manifest"; }
@@ -795,9 +806,6 @@ struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
795 SerializeFlags flags) const override { 806 SerializeFlags flags) const override {
796 appendAttr(root, "version", m.getMetaVersion()); 807 appendAttr(root, "version", m.getMetaVersion());
797 appendAttr(root, "type", m.mType); 808 appendAttr(root, "type", m.mType);
798 if (m.mLevel != Level::UNSPECIFIED) {
799 this->appendAttr(root, "target-level", m.mLevel);
800 }
801 809
802 if (!(flags & SerializeFlag::NO_HALS)) { 810 if (!(flags & SerializeFlag::NO_HALS)) {
803 appendChildren(root, manifestHalConverter, m.getHals(), d); 811 appendChildren(root, manifestHalConverter, m.getHals(), d);
@@ -806,6 +814,9 @@ struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
806 if (!(flags & SerializeFlag::NO_SEPOLICY)) { 814 if (!(flags & SerializeFlag::NO_SEPOLICY)) {
807 appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d)); 815 appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
808 } 816 }
817 if (m.mLevel != Level::UNSPECIFIED) {
818 this->appendAttr(root, "target-level", m.mLevel);
819 }
809 } else if (m.mType == SchemaType::FRAMEWORK) { 820 } else if (m.mType == SchemaType::FRAMEWORK) {
810 if (!(flags & SerializeFlag::NO_VNDK)) { 821 if (!(flags & SerializeFlag::NO_VNDK)) {
811#pragma clang diagnostic push 822#pragma clang diagnostic push
@@ -826,17 +837,16 @@ struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
826 appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d); 837 appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d);
827 } 838 }
828 } 839 }
829 bool buildObject(HalManifest *object, NodeType *root) const override { 840 bool buildObject(HalManifest* object, NodeType* root, std::string* error) const override {
830 std::vector<ManifestHal> hals; 841 std::vector<ManifestHal> hals;
831 if (!parseAttr(root, "version", &object->mMetaVersion) || 842 if (!parseAttr(root, "version", &object->mMetaVersion, error) ||
832 !parseAttr(root, "type", &object->mType) || 843 !parseAttr(root, "type", &object->mType, error) ||
833 !parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel) || 844 !parseChildren(root, manifestHalConverter, &hals, error)) {
834 !parseChildren(root, manifestHalConverter, &hals)) {
835 return false; 845 return false;
836 } 846 }
837 if (!kMetaVersion.minorAtLeast(object->mMetaVersion)) { 847 if (!kMetaVersion.minorAtLeast(object->mMetaVersion)) {
838 this->mLastError = "Unrecognized manifest.version " + to_string(object->mMetaVersion) + 848 *error = "Unrecognized manifest.version " + to_string(object->mMetaVersion) +
839 " (libvintf@" + to_string(kMetaVersion) + ")"; 849 " (libvintf@" + to_string(kMetaVersion) + ")";
840 return false; 850 return false;
841 } 851 }
842 if (object->mType == SchemaType::DEVICE) { 852 if (object->mType == SchemaType::DEVICE) {
@@ -844,59 +854,64 @@ struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
844 // <sepolicy> can be missing because it can be determined at build time, not hard-coded 854 // <sepolicy> can be missing because it can be determined at build time, not hard-coded
845 // in the XML file. 855 // in the XML file.
846 if (!parseOptionalChild(root, halManifestSepolicyConverter, {}, 856 if (!parseOptionalChild(root, halManifestSepolicyConverter, {},
847 &object->device.mSepolicyVersion)) { 857 &object->device.mSepolicyVersion, error)) {
858 return false;
859 }
860
861 if (!parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
862 error)) {
848 return false; 863 return false;
849 } 864 }
850 } else if (object->mType == SchemaType::FRAMEWORK) { 865 } else if (object->mType == SchemaType::FRAMEWORK) {
851#pragma clang diagnostic push 866#pragma clang diagnostic push
852#pragma clang diagnostic ignored "-Wdeprecated-declarations" 867#pragma clang diagnostic ignored "-Wdeprecated-declarations"
853 if (!parseChildren(root, vndkConverter, &object->framework.mVndks)) { 868 if (!parseChildren(root, vndkConverter, &object->framework.mVndks, error)) {
854 return false; 869 return false;
855 } 870 }
856 for (const auto &vndk : object->framework.mVndks) { 871 for (const auto &vndk : object->framework.mVndks) {
857 if (!vndk.mVersionRange.isSingleVersion()) { 872 if (!vndk.mVersionRange.isSingleVersion()) {
858 this->mLastError = "vndk.version " + to_string(vndk.mVersionRange) 873 *error = "vndk.version " + to_string(vndk.mVersionRange) +
859 + " cannot be a range for manifests"; 874 " cannot be a range for manifests";
860 return false; 875 return false;
861 } 876 }
862 } 877 }
863#pragma clang diagnostic pop 878#pragma clang diagnostic pop
864 879
865 if (!parseChildren(root, vendorNdkConverter, &object->framework.mVendorNdks)) { 880 if (!parseChildren(root, vendorNdkConverter, &object->framework.mVendorNdks, error)) {
866 return false; 881 return false;
867 } 882 }
868 883
869 std::set<std::string> vendorNdkVersions; 884 std::set<std::string> vendorNdkVersions;
870 for (const auto& vendorNdk : object->framework.mVendorNdks) { 885 for (const auto& vendorNdk : object->framework.mVendorNdks) {
871 if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) { 886 if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) {
872 this->mLastError = 887 *error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version();
873 "Duplicated manifest.vendor-ndk.version " + vendorNdk.version();
874 return false; 888 return false;
875 } 889 }
876 vendorNdkVersions.insert(vendorNdk.version()); 890 vendorNdkVersions.insert(vendorNdk.version());
877 } 891 }
878 892
879 if (!parseOptionalChild(root, systemSdkConverter, {}, &object->framework.mSystemSdk)) { 893 if (!parseOptionalChild(root, systemSdkConverter, {}, &object->framework.mSystemSdk,
894 error)) {
880 return false; 895 return false;
881 } 896 }
882 } 897 }
883 for (auto &&hal : hals) { 898 for (auto &&hal : hals) {
884 std::string description{hal.name}; 899 std::string description{hal.name};
885 if (!object->add(std::move(hal))) { 900 if (!object->add(std::move(hal))) {
886 this->mLastError = "Duplicated manifest.hal entry " + description; 901 *error = "Duplicated manifest.hal entry " + description;
887 return false; 902 return false;
888 } 903 }
889 } 904 }
890 905
891 std::vector<ManifestXmlFile> xmlFiles; 906 std::vector<ManifestXmlFile> xmlFiles;
892 if (!parseChildren(root, manifestXmlFileConverter, &xmlFiles)) { 907 if (!parseChildren(root, manifestXmlFileConverter, &xmlFiles, error)) {
893 return false; 908 return false;
894 } 909 }
895 for (auto&& xmlFile : xmlFiles) { 910 for (auto&& xmlFile : xmlFiles) {
896 std::string description{xmlFile.name()}; 911 std::string description{xmlFile.name()};
897 if (!object->addXmlFile(std::move(xmlFile))) { 912 if (!object->addXmlFile(std::move(xmlFile))) {
898 this->mLastError = "Duplicated manifest.xmlfile entry " + description + 913 *error = "Duplicated manifest.xmlfile entry " + description +
899 "; entries cannot have duplicated name and version"; 914 "; entries cannot have duplicated name and version";
900 return false; 915 return false;
901 } 916 }
902 } 917 }
@@ -905,19 +920,19 @@ struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
905 } 920 }
906}; 921};
907 922
908const HalManifestConverter halManifestConverter{}; 923HalManifestConverter halManifestConverter{};
909 924
910const XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"}; 925XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"};
911struct AvbConverter : public XmlNodeConverter<Version> { 926struct AvbConverter : public XmlNodeConverter<Version> {
912 std::string elementName() const override { return "avb"; } 927 std::string elementName() const override { return "avb"; }
913 void mutateNode(const Version &m, NodeType *root, DocType *d) const override { 928 void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
914 appendChild(root, avbVersionConverter(m, d)); 929 appendChild(root, avbVersionConverter(m, d));
915 } 930 }
916 bool buildObject(Version *object, NodeType *root) const override { 931 bool buildObject(Version* object, NodeType* root, std::string* error) const override {
917 return parseChild(root, avbVersionConverter, object); 932 return parseChild(root, avbVersionConverter, object, error);
918 } 933 }
919}; 934};
920const AvbConverter avbConverter{}; 935AvbConverter avbConverter{};
921 936
922struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> { 937struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> {
923 std::string elementName() const override { return "xmlfile"; } 938 std::string elementName() const override { return "xmlfile"; }
@@ -930,18 +945,18 @@ struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> {
930 appendTextElement(root, "path", f.overriddenPath(), d); 945 appendTextElement(root, "path", f.overriddenPath(), d);
931 } 946 }
932 } 947 }
933 bool buildObject(MatrixXmlFile* object, NodeType* root) const override { 948 bool buildObject(MatrixXmlFile* object, NodeType* root, std::string* error) const override {
934 if (!parseTextElement(root, "name", &object->mName) || 949 if (!parseTextElement(root, "name", &object->mName, error) ||
935 !parseAttr(root, "format", &object->mFormat) || 950 !parseAttr(root, "format", &object->mFormat, error) ||
936 !parseOptionalAttr(root, "optional", false, &object->mOptional) || 951 !parseOptionalAttr(root, "optional", false, &object->mOptional, error) ||
937 !parseChild(root, versionRangeConverter, &object->mVersionRange) || 952 !parseChild(root, versionRangeConverter, &object->mVersionRange, error) ||
938 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath)) { 953 !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) {
939 return false; 954 return false;
940 } 955 }
941 return true; 956 return true;
942 } 957 }
943}; 958};
944const MatrixXmlFileConverter matrixXmlFileConverter{}; 959MatrixXmlFileConverter matrixXmlFileConverter{};
945 960
946struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> { 961struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
947 std::string elementName() const override { return "compatibility-matrix"; } 962 std::string elementName() const override { return "compatibility-matrix"; }
@@ -952,9 +967,6 @@ struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatri
952 SerializeFlags flags) const override { 967 SerializeFlags flags) const override {
953 appendAttr(root, "version", m.getMinimumMetaVersion()); 968 appendAttr(root, "version", m.getMinimumMetaVersion());
954 appendAttr(root, "type", m.mType); 969 appendAttr(root, "type", m.mType);
955 if (m.mLevel != Level::UNSPECIFIED) {
956 this->appendAttr(root, "level", m.mLevel);
957 }
958 970
959 if (!(flags & SerializeFlag::NO_HALS)) { 971 if (!(flags & SerializeFlag::NO_HALS)) {
960 appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d); 972 appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d);
@@ -973,6 +985,9 @@ struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatri
973 appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d)); 985 appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d));
974 } 986 }
975 } 987 }
988 if (m.mLevel != Level::UNSPECIFIED) {
989 this->appendAttr(root, "level", m.mLevel);
990 }
976 } else if (m.mType == SchemaType::DEVICE) { 991 } else if (m.mType == SchemaType::DEVICE) {
977 if (!(flags & SerializeFlag::NO_VNDK)) { 992 if (!(flags & SerializeFlag::NO_VNDK)) {
978#pragma clang diagnostic push 993#pragma clang diagnostic push
@@ -998,21 +1013,24 @@ struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatri
998 appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d); 1013 appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d);
999 } 1014 }
1000 } 1015 }
1001 bool buildObject(CompatibilityMatrix *object, NodeType *root) const override { 1016 bool buildObject(CompatibilityMatrix* object, NodeType* root,
1017 std::string* error) const override {
1002 Version version; 1018 Version version;
1003 std::vector<MatrixHal> hals; 1019 std::vector<MatrixHal> hals;
1004 if (!parseAttr(root, "version", &version) || !parseAttr(root, "type", &object->mType) || 1020 if (!parseAttr(root, "version", &version, error) ||
1005 !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel) || 1021 !parseAttr(root, "type", &object->mType, error) ||
1006 !parseChildren(root, matrixHalConverter, &hals)) { 1022 !parseChildren(root, matrixHalConverter, &hals, error)) {
1007 return false; 1023 return false;
1008 } 1024 }
1009 1025
1010 if (object->mType == SchemaType::FRAMEWORK) { 1026 if (object->mType == SchemaType::FRAMEWORK) {
1011 // <avb> and <sepolicy> can be missing because it can be determined at build time, not 1027 // <avb> and <sepolicy> can be missing because it can be determined at build time, not
1012 // hard-coded in the XML file. 1028 // hard-coded in the XML file.
1013 if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels) || 1029 if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels, error) ||
1014 !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy) || 1030 !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy,
1015 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion)) { 1031 error) ||
1032 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion,
1033 error)) {
1016 return false; 1034 return false;
1017 } 1035 }
1018 1036
@@ -1023,57 +1041,63 @@ struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatri
1023 continue; 1041 continue;
1024 } 1042 }
1025 if (!kernel.conditions().empty()) { 1043 if (!kernel.conditions().empty()) {
1026 this->mLastError = "First <kernel> for version " + to_string(minLts) + 1044 *error = "First <kernel> for version " + to_string(minLts) +
1027 " must have empty <conditions> for backwards compatibility."; 1045 " must have empty <conditions> for backwards compatibility.";
1028 return false; 1046 return false;
1029 } 1047 }
1030 seenKernelVersions.insert(minLts); 1048 seenKernelVersions.insert(minLts);
1031 } 1049 }
1032 1050
1051 if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel, error)) {
1052 return false;
1053 }
1054
1033 } else if (object->mType == SchemaType::DEVICE) { 1055 } else if (object->mType == SchemaType::DEVICE) {
1034 // <vndk> can be missing because it can be determined at build time, not hard-coded 1056 // <vndk> can be missing because it can be determined at build time, not hard-coded
1035 // in the XML file. 1057 // in the XML file.
1036#pragma clang diagnostic push 1058#pragma clang diagnostic push
1037#pragma clang diagnostic ignored "-Wdeprecated-declarations" 1059#pragma clang diagnostic ignored "-Wdeprecated-declarations"
1038 if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk)) { 1060 if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk, error)) {
1039 return false; 1061 return false;
1040 } 1062 }
1041#pragma clang diagnostic pop 1063#pragma clang diagnostic pop
1042 1064
1043 if (!parseOptionalChild(root, vendorNdkConverter, {}, &object->device.mVendorNdk)) { 1065 if (!parseOptionalChild(root, vendorNdkConverter, {}, &object->device.mVendorNdk,
1066 error)) {
1044 return false; 1067 return false;
1045 } 1068 }
1046 1069
1047 if (!parseOptionalChild(root, systemSdkConverter, {}, &object->device.mSystemSdk)) { 1070 if (!parseOptionalChild(root, systemSdkConverter, {}, &object->device.mSystemSdk,
1071 error)) {
1048 return false; 1072 return false;
1049 } 1073 }
1050 } 1074 }
1051 1075
1052 if (!kMetaVersion.minorAtLeast(version)) { 1076 if (!kMetaVersion.minorAtLeast(version)) {
1053 this->mLastError = "Unrecognized compatibility-matrix.version " + to_string(version) + 1077 *error = "Unrecognized compatibility-matrix.version " + to_string(version) +
1054 " (libvintf@" + to_string(kMetaVersion) + ")"; 1078 " (libvintf@" + to_string(kMetaVersion) + ")";
1055 return false; 1079 return false;
1056 } 1080 }
1057 for (auto &&hal : hals) { 1081 for (auto &&hal : hals) {
1058 if (!object->add(std::move(hal))) { 1082 if (!object->add(std::move(hal))) {
1059 this->mLastError = "Duplicated compatibility-matrix.hal entry"; 1083 *error = "Duplicated compatibility-matrix.hal entry";
1060 return false; 1084 return false;
1061 } 1085 }
1062 } 1086 }
1063 1087
1064 std::vector<MatrixXmlFile> xmlFiles; 1088 std::vector<MatrixXmlFile> xmlFiles;
1065 if (!parseChildren(root, matrixXmlFileConverter, &xmlFiles)) { 1089 if (!parseChildren(root, matrixXmlFileConverter, &xmlFiles, error)) {
1066 return false; 1090 return false;
1067 } 1091 }
1068 for (auto&& xmlFile : xmlFiles) { 1092 for (auto&& xmlFile : xmlFiles) {
1069 if (!xmlFile.optional()) { 1093 if (!xmlFile.optional()) {
1070 this->mLastError = "compatibility-matrix.xmlfile entry " + xmlFile.name() + 1094 *error = "compatibility-matrix.xmlfile entry " + xmlFile.name() +
1071 " has to be optional for compatibility matrix version 1.0"; 1095 " has to be optional for compatibility matrix version 1.0";
1072 return false; 1096 return false;
1073 } 1097 }
1074 std::string description{xmlFile.name()}; 1098 std::string description{xmlFile.name()};
1075 if (!object->addXmlFile(std::move(xmlFile))) { 1099 if (!object->addXmlFile(std::move(xmlFile))) {
1076 this->mLastError = "Duplicated compatibility-matrix.xmlfile entry " + description; 1100 *error = "Duplicated compatibility-matrix.xmlfile entry " + description;
1077 return false; 1101 return false;
1078 } 1102 }
1079 } 1103 }
@@ -1082,19 +1106,18 @@ struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatri
1082 } 1106 }
1083}; 1107};
1084 1108
1085const CompatibilityMatrixConverter compatibilityMatrixConverter{}; 1109CompatibilityMatrixConverter compatibilityMatrixConverter{};
1086 1110
1087// Publicly available as in parse_xml.h 1111// Publicly available as in parse_xml.h
1088const XmlConverter<HalManifest> &gHalManifestConverter = halManifestConverter; 1112XmlConverter<HalManifest>& gHalManifestConverter = halManifestConverter;
1089const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter 1113XmlConverter<CompatibilityMatrix>& gCompatibilityMatrixConverter = compatibilityMatrixConverter;
1090 = compatibilityMatrixConverter;
1091 1114
1092// For testing in LibVintfTest 1115// For testing in LibVintfTest
1093const XmlConverter<Version> &gVersionConverter = versionConverter; 1116XmlConverter<Version>& gVersionConverter = versionConverter;
1094const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter 1117XmlConverter<KernelConfigTypedValue>& gKernelConfigTypedValueConverter =
1095 = kernelConfigTypedValueConverter; 1118 kernelConfigTypedValueConverter;
1096const XmlConverter<MatrixHal> &gMatrixHalConverter = matrixHalConverter; 1119XmlConverter<MatrixHal>& gMatrixHalConverter = matrixHalConverter;
1097const XmlConverter<ManifestHal> &gManifestHalConverter = manifestHalConverter; 1120XmlConverter<ManifestHal>& gManifestHalConverter = manifestHalConverter;
1098 1121
1099} // namespace vintf 1122} // namespace vintf
1100} // namespace android 1123} // namespace android
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index ef19a4c..6eedf01 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -32,12 +32,12 @@
32namespace android { 32namespace android {
33namespace vintf { 33namespace vintf {
34 34
35extern const XmlConverter<Version> &gVersionConverter; 35extern XmlConverter<Version>& gVersionConverter;
36extern const XmlConverter<ManifestHal> &gManifestHalConverter; 36extern XmlConverter<ManifestHal>& gManifestHalConverter;
37extern const XmlConverter<MatrixHal> &gMatrixHalConverter; 37extern XmlConverter<MatrixHal>& gMatrixHalConverter;
38extern const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter; 38extern XmlConverter<KernelConfigTypedValue>& gKernelConfigTypedValueConverter;
39extern const XmlConverter<HalManifest> &gHalManifestConverter; 39extern XmlConverter<HalManifest>& gHalManifestConverter;
40extern const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter; 40extern XmlConverter<CompatibilityMatrix>& gCompatibilityMatrixConverter;
41 41
42static bool In(const std::string& sub, const std::string& str) { 42static bool In(const std::string& sub, const std::string& str) {
43 return str.find(sub) != std::string::npos; 43 return str.find(sub) != std::string::npos;
@@ -2749,6 +2749,33 @@ TEST_F(LibVintfTest, SystemSdk) {
2749 } 2749 }
2750} 2750}
2751 2751
2752TEST_F(LibVintfTest, ManifestLastError) {
2753 HalManifest e;
2754 // Set mLastError to something else before testing.
2755 EXPECT_FALSE(gHalManifestConverter(&e, "<manifest/>"));
2756 EXPECT_NE("Not a valid XML", gHalManifestConverter.lastError());
2757
2758 std::string error;
2759 std::string prevError = gHalManifestConverter.lastError();
2760 EXPECT_FALSE(gHalManifestConverter(&e, "", &error));
2761 EXPECT_EQ("Not a valid XML", error);
2762 EXPECT_EQ(prevError, gHalManifestConverter.lastError()) << "lastError() should not be modified";
2763}
2764
2765TEST_F(LibVintfTest, MatrixLastError) {
2766 CompatibilityMatrix e;
2767 // Set mLastError to something else before testing.
2768 EXPECT_FALSE(gCompatibilityMatrixConverter(&e, "<compatibility-matrix/>"));
2769 EXPECT_NE("Not a valid XML", gCompatibilityMatrixConverter.lastError());
2770
2771 std::string error;
2772 std::string prevError = gCompatibilityMatrixConverter.lastError();
2773 EXPECT_FALSE(gCompatibilityMatrixConverter(&e, "", &error));
2774 EXPECT_EQ("Not a valid XML", error);
2775 EXPECT_EQ(prevError, gCompatibilityMatrixConverter.lastError())
2776 << "lastError() should not be modified";
2777}
2778
2752} // namespace vintf 2779} // namespace vintf
2753} // namespace android 2780} // namespace android
2754 2781
diff --git a/utils.h b/utils.h
index 3779614..305a018 100644
--- a/utils.h
+++ b/utils.h
@@ -110,10 +110,10 @@ status_t fetchAllInformation(const std::string& path, const XmlConverter<T>& con
110 return result; 110 return result;
111 } 111 }
112 112
113 bool success = converter(outObject, info); 113 bool success = converter(outObject, info, error);
114 if (!success) { 114 if (!success) {
115 if (error) { 115 if (error) {
116 *error = "Illformed file: " + path + ": " + converter.lastError(); 116 *error = "Illformed file: " + path + ": " + *error;
117 } 117 }
118 return BAD_VALUE; 118 return BAD_VALUE;
119 } 119 }