Add product matrix FCM levels.
Read all files in /product/etc/vintf and treat files the same way
we treat system matrix at each FCM level in /system/etc/vintf.
Bug: 140360109
Test: vintf_object_test
Change-Id: I0a74b7aa3001c4491f264f36bb2093cd97ac04bf
diff --git a/VintfObject.cpp b/VintfObject.cpp
index b706599..5c9f8d9 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -23,6 +23,7 @@
#include <mutex>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include "CompatibilityMatrix.h"
#include "parse_string.h"
@@ -401,43 +402,48 @@
status_t VintfObject::getAllFrameworkMatrixLevels(std::vector<Named<CompatibilityMatrix>>* results,
std::string* error) {
- std::vector<std::string> fileNames;
-
- status_t listStatus = getFileSystem()->listFiles(kSystemVintfDir, &fileNames, error);
- if (listStatus != OK) {
- return listStatus;
- }
- for (const std::string& fileName : fileNames) {
- std::string path = kSystemVintfDir + fileName;
- Named<CompatibilityMatrix> namedMatrix;
- std::string matrixError;
- status_t matrixStatus = getOneMatrix(path, &namedMatrix, &matrixError);
- if (matrixStatus != OK) {
- // System manifests and matrices share the same dir. Client may not have enough
- // permissions to read system manifests, or may not be able to parse it.
- auto logLevel = matrixStatus == BAD_VALUE ? base::DEBUG : base::ERROR;
- LOG(logLevel) << "Framework Matrix: Ignore file " << path << ": " << matrixError;
+ std::vector<std::string> dirs = {
+ kSystemVintfDir,
+ kProductVintfDir,
+ };
+ for (const auto& dir : dirs) {
+ std::vector<std::string> fileNames;
+ status_t listStatus = getFileSystem()->listFiles(dir, &fileNames, error);
+ if (listStatus == NAME_NOT_FOUND) {
continue;
}
- results->emplace_back(std::move(namedMatrix));
- }
+ if (listStatus != OK) {
+ return listStatus;
+ }
+ for (const std::string& fileName : fileNames) {
+ std::string path = dir + fileName;
+ Named<CompatibilityMatrix> namedMatrix;
+ std::string matrixError;
+ status_t matrixStatus = getOneMatrix(path, &namedMatrix, &matrixError);
+ if (matrixStatus != OK) {
+ // Manifests and matrices share the same dir. Client may not have enough
+ // permissions to read system manifests, or may not be able to parse it.
+ auto logLevel = matrixStatus == BAD_VALUE ? base::DEBUG : base::ERROR;
+ LOG(logLevel) << "Framework Matrix: Ignore file " << path << ": " << matrixError;
+ continue;
+ }
+ results->emplace_back(std::move(namedMatrix));
+ }
- Named<CompatibilityMatrix> productMatrix;
- std::string productError;
- status_t productStatus = getOneMatrix(kProductMatrix, &productMatrix, &productError);
- if (productStatus == OK) {
- results->emplace_back(std::move(productMatrix));
- } else if (productStatus == NAME_NOT_FOUND) {
- LOG(DEBUG) << "Framework Matrix: missing " << kProductMatrix;
- } else {
- if (error) *error = std::move(productError);
- return productStatus;
+ if (dir == kSystemVintfDir && results->empty()) {
+ if (error) {
+ *error = "No framework matrices under " + dir + " can be fetched or parsed.\n";
+ }
+ return NAME_NOT_FOUND;
+ }
}
if (results->empty()) {
if (error) {
*error =
- "No framework matrices under " + kSystemVintfDir + " can be fetched or parsed.\n";
+ "No framework matrices can be fetched or parsed. "
+ "The following directories are searched:\n " +
+ android::base::Join(dirs, "\n ");
}
return NAME_NOT_FOUND;
}
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index bcf753c..31e54a1 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <unistd.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/strings.h>
#include <hidl-util/FQName.h>
@@ -32,6 +31,7 @@
#include "utils-fake.h"
using namespace ::testing;
+using namespace std::literals;
using android::FqInstance;
@@ -618,6 +618,11 @@
};
return ::android::OK;
}));
+ EXPECT_CALL(fetcher(), listFiles(StrEq(kProductVintfDir), _, _))
+ .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) {
+ *out = {android::base::Basename(kProductMatrix)};
+ return ::android::OK;
+ }));
expectFetch(kSystemVintfDir + "compatibility_matrix.1.xml",
"<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"1\"/>");
expectFetch(kSystemVintfDir + "compatibility_matrix.empty.xml",
@@ -983,7 +988,10 @@
return "compatibility_matrix." + std::to_string(static_cast<Level>(i)) + ".xml";
}
void SetUpMockSystemMatrices(const std::vector<std::string>& xmls) {
- EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _))
+ SetUpMockMatrices(kSystemVintfDir, xmls);
+ }
+ void SetUpMockMatrices(const std::string& dir, const std::vector<std::string>& xmls) {
+ EXPECT_CALL(fetcher(), listFiles(StrEq(dir), _, _))
.WillRepeatedly(Invoke([=](const auto&, auto* out, auto*) {
size_t i = 1;
for (const auto& content : xmls) {
@@ -995,12 +1003,9 @@
}));
size_t i = 1;
for (const auto& content : xmls) {
- expectFetchRepeatedly(kSystemVintfDir + getFileName(i), content);
+ expectFetchRepeatedly(dir + getFileName(i), content);
++i;
}
- expectFileNotExist(kProductMatrix);
- expectNeverFetch(kSystemLegacyMatrix);
- expectFileNotExist(StartsWith("/odm/"));
}
void expectTargetFcmVersion(size_t level) {
expectFetch(kVendorManifest, "<manifest " + kMetaVersionStr + " type=\"device\" target-level=\"" +
@@ -1578,6 +1583,91 @@
INSTANTIATE_TEST_SUITE_P(Vintf, FrameworkManifestTest,
::testing::Combine(Bool(), Bool(), Bool(), Bool()));
+
+//
+// Set of OEM FCM matrices at different FCM version.
+//
+
+std::vector<std::string> GetOemFcmMatrixLevels(const std::string& name) {
+ return {
+ // 1.xml
+ "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"1\">\n"
+ " <hal format=\"hidl\" optional=\"true\">\n"
+ " <name>vendor.foo." + name + "</name>\n"
+ " <version>1.0</version>\n"
+ " <interface>\n"
+ " <name>IExtra</name>\n"
+ " <instance>default</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ "</compatibility-matrix>\n",
+ // 2.xml
+ "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"2\">\n"
+ " <hal format=\"hidl\" optional=\"true\">\n"
+ " <name>vendor.foo." + name + "</name>\n"
+ " <version>2.0</version>\n"
+ " <interface>\n"
+ " <name>IExtra</name>\n"
+ " <instance>default</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ "</compatibility-matrix>\n",
+ };
+}
+
+class OemFcmLevelTest : public MultiMatrixTest,
+ public WithParamInterface<std::tuple<size_t, bool>> {
+ protected:
+ virtual void SetUp() override {
+ MultiMatrixTest::SetUp();
+ SetUpMockSystemMatrices({systemMatrixLevel1, systemMatrixLevel2});
+ }
+ using Instances = std::set<std::string>;
+ Instances GetInstances(const CompatibilityMatrix* fcm) {
+ Instances instances;
+ fcm->forEachHidlInstance([&instances](const auto& matrixInstance) {
+ instances.insert(matrixInstance.description(matrixInstance.versionRange().minVer()));
+ return true; // continue
+ });
+ return instances;
+ }
+};
+
+TEST_P(OemFcmLevelTest, Test) {
+ auto&& [level, hasProduct] = GetParam();
+
+ expectTargetFcmVersion(level);
+ if (hasProduct) {
+ SetUpMockMatrices(kProductVintfDir, GetOemFcmMatrixLevels("product"));
+ }
+
+ auto fcm = vintfObject->getFrameworkCompatibilityMatrix();
+ ASSERT_NE(nullptr, fcm);
+ auto instances = GetInstances(fcm.get());
+
+ auto containsOrNot = [](bool contains, const std::string& e) {
+ return contains ? SafeMatcherCast<Instances>(Contains(e))
+ : SafeMatcherCast<Instances>(Not(Contains(e)));
+ };
+
+ EXPECT_THAT(instances, containsOrNot(level == 1,
+ "android.hardware.major@1.0::IMajor/default"));
+ EXPECT_THAT(instances, containsOrNot(level == 1 && hasProduct,
+ "vendor.foo.product@1.0::IExtra/default"));
+ EXPECT_THAT(instances, Contains("android.hardware.major@2.0::IMajor/default"));
+ EXPECT_THAT(instances, containsOrNot(hasProduct,
+ "vendor.foo.product@2.0::IExtra/default"));
+}
+
+static std::string OemFcmLevelTestParamToString(
+ const TestParamInfo<OemFcmLevelTest::ParamType>& info) {
+ auto&& [level, hasProduct] = info.param;
+ auto name = "Level" + std::to_string(level);
+ name += "With"s + (hasProduct ? "" : "out") + "Product";
+ return name;
+}
+INSTANTIATE_TEST_SUITE_P(OemFcmLevel, OemFcmLevelTest, Combine(Values(1, 2), Bool()),
+ OemFcmLevelTestParamToString);
// clang-format on
} // namespace testing