assemble_vintf: move logic to CompatibilityMatrix::combine
... that combines <hal> and <xmlfile> elements of a list
of comp matrices.
* All required HALs at deviceLevel will be required in output matrix.
* All HALs at level > deviceLevel will be optional in output matrix.
The logic is also improved in the following ways:
* <xmlfile>s are also handled
* <hal>s and <xmlfile>s are moved to the "unspecified" matrix (that has non-hal
/ xmlfile information)
Test: libvintf_test
Bug: 69636193
Change-Id: Ifdc2227d1823840c0303ce6476ffa4b542e04e12
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 1e7d542..98d4414 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -21,6 +21,9 @@
#include "parse_string.h"
#include "utils.h"
+#include <iostream>
+#include "parse_xml.h"
+
namespace android {
namespace vintf {
@@ -166,5 +169,123 @@
lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
}
+// Find compatibility_matrix.empty.xml (which has unspecified level) and use it
+// as a base matrix.
+CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix(
+ std::vector<std::pair<std::string, CompatibilityMatrix>>* matrices, std::string* error) {
+ bool multipleFound = false;
+ CompatibilityMatrix* matrix = nullptr;
+ for (auto& e : *matrices) {
+ if (e.second.level() == Level::UNSPECIFIED) {
+ if (!e.second.mHals.empty()) {
+ if (error) {
+ *error =
+ "Error: File \"" + e.first + "\" should not contain " + "HAL elements.";
+ }
+ return nullptr;
+ }
+
+ if (!e.second.mXmlFiles.empty()) {
+ if (error) {
+ *error = "Error: File \"" + e.first + "\" should not contain " +
+ "XML File elements.";
+ }
+ return nullptr;
+ }
+
+ if (matrix != nullptr) {
+ multipleFound = true;
+ }
+
+ matrix = &e.second;
+ // continue to detect multiple files with "unspecified" levels
+ }
+ }
+
+ if (multipleFound) {
+ if (error) {
+ *error =
+ "Error: multiple framework compatibility matrix files have "
+ "unspecified level; there should only be one such file.\n";
+ for (auto& e : *matrices) {
+ if (e.second.level() == Level::UNSPECIFIED) {
+ *error += " " + e.first + "\n";
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ if (matrix == nullptr) {
+ matrix = &matrices->emplace(matrices->end())->second;
+ matrix->mType = SchemaType::FRAMEWORK;
+ matrix->mLevel = Level::UNSPECIFIED;
+ }
+
+ return matrix;
+}
+
+CompatibilityMatrix* CompatibilityMatrix::combine(
+ Level deviceLevel, std::vector<std::pair<std::string, CompatibilityMatrix>>* matrices,
+ std::string* error) {
+ if (deviceLevel == Level::UNSPECIFIED) {
+ if (error) {
+ *error = "Error: device level is unspecified.";
+ }
+ return nullptr;
+ }
+
+ CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error);
+ if (matrix == nullptr) {
+ return nullptr;
+ }
+
+ matrix->mLevel = deviceLevel;
+
+ for (auto& e : *matrices) {
+ if (&e.second != matrix && e.second.level() == deviceLevel) {
+ if (!matrix->addAllHals(&e.second, error)) {
+ if (error) {
+ *error = "File \"" + e.first + "\" cannot be added: HAL " + *error +
+ " has a conflict.";
+ }
+ return nullptr;
+ }
+
+ if (!matrix->addAllXmlFiles(&e.second, error)) {
+ if (error) {
+ *error = "File \"" + e.first + "\" cannot be added: XML File entry " + *error +
+ " has a conflict.";
+ }
+ return nullptr;
+ }
+ }
+ }
+
+ for (auto& e : *matrices) {
+ if (&e.second != matrix && e.second.level() != Level::UNSPECIFIED &&
+ e.second.level() > deviceLevel) {
+ if (!matrix->addAllHalsAsOptional(&e.second, error)) {
+ if (error) {
+ *error = "File \"" + e.first + "\" cannot be added: " + *error +
+ ". See <hal> with the same name " +
+ "in previously parsed files or previously declared in this file.";
+ }
+ return nullptr;
+ }
+
+ if (!matrix->addAllXmlFilesAsOptional(&e.second, error)) {
+ if (error) {
+ *error = "File \"" + e.first + "\" cannot be added: XML File entry " + *error +
+ " has a conflict.";
+ }
+ return nullptr;
+ }
+ }
+ }
+
+ return matrix;
+}
+
} // namespace vintf
} // namespace android