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/AssembleVintf.cpp b/AssembleVintf.cpp
index 4665f68..4174e93 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -420,7 +420,6 @@
if (matrices->front().second.mType == SchemaType::FRAMEWORK) {
Level deviceLevel = Level::UNSPECIFIED;
- std::vector<std::string> fileList;
if (mCheckFile != nullptr) {
checkManifest = std::make_unique<HalManifest>();
if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile))) {
@@ -437,27 +436,13 @@
deviceLevel = getLowestFcmVersion(*matrices);
}
- for (auto& e : *matrices) {
- if (e.second.level() == deviceLevel) {
- fileList.push_back(e.first);
- matrix = &e.second;
- }
- }
- if (matrix == nullptr) {
- std::cerr << "FATAL ERROR: cannot find matrix with level '" << deviceLevel << "'"
- << std::endl;
- return false;
- }
- for (auto& e : *matrices) {
- if (e.second.level() <= deviceLevel) {
- continue;
- }
- fileList.push_back(e.first);
- if (!matrix->addAllHalsAsOptional(&e.second, &error)) {
- std::cerr << "File \"" << e.first << "\" cannot be added: " << error
- << ". See <hal> with the same name "
- << "in previously parsed files or previously declared in this file."
- << std::endl;
+ if (deviceLevel == Level::UNSPECIFIED) {
+ // building empty.xml
+ matrix = &matrices->front().second;
+ } else {
+ matrix = CompatibilityMatrix::combine(deviceLevel, matrices, &error);
+ if (matrix == nullptr) {
+ std::cerr << error << std::endl;
return false;
}
}
@@ -484,8 +469,10 @@
out() << "<!--" << std::endl;
out() << " Input:" << std::endl;
- for (const auto& path : fileList) {
- out() << " " << getFileNameFromPath(path) << std::endl;
+ for (const auto& e : *matrices) {
+ if (!e.first.empty()) {
+ out() << " " << getFileNameFromPath(e.first) << std::endl;
+ }
}
out() << "-->" << std::endl;
}
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
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 4aa1cb3..9be80ed 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -73,6 +73,19 @@
status_t fetchAllInformation(const std::string& path, std::string* error = nullptr);
+ // Combine a subset of "matrices". For each CompatibilityMatrix in matrices,
+ // - If level() == UNSPECIFIED, use it as the base matrix (for non-HAL, non-XML-file
+ // requirements).
+ // - If level() < deviceLevel, ignore
+ // - If level() == deviceLevel, all HAL versions and XML files are added as is
+ // (optionality is kept)
+ // - If level() > deviceLevel, all HAL versions and XML files are added as optional.
+ static CompatibilityMatrix* combine(
+ Level deviceLevel, std::vector<std::pair<std::string, CompatibilityMatrix>>* matrices,
+ std::string* error);
+ static CompatibilityMatrix* findOrInsertBaseMatrix(
+ std::vector<std::pair<std::string, CompatibilityMatrix>>* matrices, std::string* error);
+
friend struct HalManifest;
friend struct RuntimeInfo;
friend struct CompatibilityMatrixConverter;