summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CompatibilityMatrix.cpp81
-rw-r--r--include/vintf/CompatibilityMatrix.h3
-rw-r--r--test/vintf_object_tests.cpp94
3 files changed, 170 insertions, 8 deletions
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 451ca60..338e5be 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -194,6 +194,36 @@ bool CompatibilityMatrix::addAllXmlFilesAsOptional(CompatibilityMatrix* other, s
194 return true; 194 return true;
195} 195}
196 196
197bool CompatibilityMatrix::addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error) {
198 if (other == nullptr || other->level() <= level()) {
199 return true;
200 }
201
202 for (MatrixKernel& kernelToAdd : other->framework.mKernels) {
203 bool exists =
204 std::any_of(this->framework.mKernels.begin(), this->framework.mKernels.end(),
205 [&kernelToAdd](const MatrixKernel& existing) {
206 return kernelToAdd.minLts().version == existing.minLts().version &&
207 kernelToAdd.minLts().majorRev == existing.minLts().majorRev;
208 });
209
210 if (exists) {
211 // Shouldn't retroactively add requirements to minLts(), so ignore this.
212 // This happens even when kernelToAdd.conditions() != existing.conditions().
213 continue;
214 }
215
216 KernelVersion minLts = kernelToAdd.minLts();
217 if (!add(std::move(kernelToAdd))) {
218 if (error) {
219 *error = "Cannot add " + to_string(minLts) + " for unknown reason.";
220 }
221 return false;
222 }
223 }
224 return true;
225}
226
197bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) { 227bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
198 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals && 228 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
199 lft.mXmlFiles == rgt.mXmlFiles && 229 lft.mXmlFiles == rgt.mXmlFiles &&
@@ -258,9 +288,32 @@ CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix(
258 return matrix; 288 return matrix;
259} 289}
260 290
291// Check if there are two files declaring level="1", for example, because
292// combine() use this assumption to simplify a lot of logic.
293static bool checkDuplicateLevels(const std::vector<Named<CompatibilityMatrix>>& matrices,
294 std::string* error) {
295 std::map<Level, const std::string*> existingLevels;
296 for (const auto& e : matrices) {
297 if (e.object.level() == Level::UNSPECIFIED &&
298 existingLevels.find(e.object.level()) != existingLevels.end()) {
299 if (error) {
300 *error = "Conflict of levels: file \"" +
301 *existingLevels.find(e.object.level())->second + "\" and \"" + e.name +
302 " both have level " + to_string(e.object.level());
303 }
304 return false;
305 }
306 existingLevels.emplace(e.object.level(), &e.name);
307 }
308 return true;
309}
310
261CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel, 311CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
262 std::vector<Named<CompatibilityMatrix>>* matrices, 312 std::vector<Named<CompatibilityMatrix>>* matrices,
263 std::string* error) { 313 std::string* error) {
314 if (!checkDuplicateLevels(*matrices, error)) {
315 return nullptr;
316 }
264 317
265 CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error); 318 CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error);
266 if (matrix == nullptr) { 319 if (matrix == nullptr) {
@@ -312,6 +365,13 @@ CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
312 } 365 }
313 } 366 }
314 367
368 // Add <kernel> from exact "level", then optionally add <kernel> from high levels to low levels.
369 // For example, (each letter is a kernel version x.y.z)
370 // 1.xml: A1, B1
371 // 2.xml: B2, C2, D2
372 // 3.xml: D3, E3
373 // Then the combined 1.xml should have
374 // A1, B1 (from 1.xml, required), C2, D2, E3 (optional, use earliest possible).
315 for (auto& e : *matrices) { 375 for (auto& e : *matrices) {
316 if (&e.object != matrix && e.object.level() == deviceLevel && 376 if (&e.object != matrix && e.object.level() == deviceLevel &&
317 e.object.type() == SchemaType::FRAMEWORK) { 377 e.object.type() == SchemaType::FRAMEWORK) {
@@ -328,6 +388,27 @@ CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel,
328 } 388 }
329 } 389 }
330 390
391 // There is only one file per level, hence a map is used instead of a multimap. Also, there is
392 // no good ordering (i.e. priority) for multiple files with the same level.
393 std::map<Level, Named<CompatibilityMatrix>*> matricesMap;
394 for (auto& e : *matrices) {
395 if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
396 e.object.level() > deviceLevel && e.object.type() == SchemaType::FRAMEWORK) {
397 matricesMap.emplace(e.object.level(), &e);
398 }
399 }
400
401 for (auto&& pair : matricesMap) {
402 if (!matrix->addAllKernelsAsOptional(&pair.second->object, error)) {
403 if (error) {
404 *error = "Cannot add new kernel versions from FCM version " +
405 to_string(pair.first) + " (" + pair.second->name + ")" +
406 " to FCM version " + to_string(deviceLevel) + ": " + *error;
407 }
408 return nullptr;
409 }
410 }
411
331 return matrix; 412 return matrix;
332} 413}
333 414
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index ff5dd24..a43d493 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -75,6 +75,9 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat
75 // Similar to addAllHalsAsOptional but on <xmlfile> entries. 75 // Similar to addAllHalsAsOptional but on <xmlfile> entries.
76 bool addAllXmlFilesAsOptional(CompatibilityMatrix* other, std::string* error); 76 bool addAllXmlFilesAsOptional(CompatibilityMatrix* other, std::string* error);
77 77
78 // Similar to addAllHalsAsOptional but on <kernel> entries.
79 bool addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error);
80
78 status_t fetchAllInformation(const std::string& path, std::string* error = nullptr); 81 status_t fetchAllInformation(const std::string& path, std::string* error = nullptr);
79 82
80 // Combine a subset of "matrices". For each CompatibilityMatrix in matrices, 83 // Combine a subset of "matrices". For each CompatibilityMatrix in matrices,
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 48623b8..86d43a4 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -34,10 +34,12 @@ using namespace ::android::vintf::details;
34 34
35using android::FqInstance; 35using android::FqInstance;
36 36
37static bool In(const std::string& sub, const std::string& str) { 37static AssertionResult In(const std::string& sub, const std::string& str) {
38 return str.find(sub) != std::string::npos; 38 return (str.find(sub) != std::string::npos ? AssertionSuccess() : AssertionFailure())
39 << "Value is " << str;
39} 40}
40#define EXPECT_IN(sub, str) EXPECT_TRUE(In((sub), (str))) << (str); 41#define EXPECT_IN(sub, str) EXPECT_TRUE(In((sub), (str)))
42#define EXPECT_NOT_IN(sub, str) EXPECT_FALSE(In((sub), (str)))
41 43
42// 44//
43// Set of Xml1 metadata compatible with each other. 45// Set of Xml1 metadata compatible with each other.
@@ -1017,16 +1019,16 @@ TEST_F(DeprecateTest, CheckMajor2) {
1017 << "major@1.0 should be deprecated. " << error; 1019 << "major@1.0 should be deprecated. " << error;
1018} 1020}
1019 1021
1020class RegexTest : public VintfObjectTestBase { 1022class MultiMatrixTest : public VintfObjectTestBase {
1021 protected: 1023 protected:
1022 static std::string getFileName(size_t i) { 1024 static std::string getFileName(size_t i) {
1023 return "compatibility_matrix." + std::to_string(static_cast<Level>(i)) + ".xml"; 1025 return "compatibility_matrix." + std::to_string(static_cast<Level>(i)) + ".xml";
1024 } 1026 }
1025 virtual void SetUp() override { 1027 void SetUpMockSystemMatrices(const std::vector<std::string>& xmls) {
1026 EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _)) 1028 EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _))
1027 .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) { 1029 .WillRepeatedly(Invoke([=](const auto&, auto* out, auto*) {
1028 size_t i = 1; 1030 size_t i = 1;
1029 for (const auto& content : systemMatrixRegexXmls) { 1031 for (const auto& content : xmls) {
1030 (void)content; 1032 (void)content;
1031 out->push_back(getFileName(i)); 1033 out->push_back(getFileName(i));
1032 ++i; 1034 ++i;
@@ -1034,7 +1036,7 @@ class RegexTest : public VintfObjectTestBase {
1034 return ::android::OK; 1036 return ::android::OK;
1035 })); 1037 }));
1036 size_t i = 1; 1038 size_t i = 1;
1037 for (const auto& content : systemMatrixRegexXmls) { 1039 for (const auto& content : xmls) {
1038 expectFetchRepeatedly(kSystemVintfDir + getFileName(i), content); 1040 expectFetchRepeatedly(kSystemVintfDir + getFileName(i), content);
1039 ++i; 1041 ++i;
1040 } 1042 }
@@ -1048,6 +1050,11 @@ class RegexTest : public VintfObjectTestBase {
1048 } 1050 }
1049}; 1051};
1050 1052
1053class RegexTest : public MultiMatrixTest {
1054 protected:
1055 virtual void SetUp() { SetUpMockSystemMatrices(systemMatrixRegexXmls); }
1056};
1057
1051TEST_F(RegexTest, CombineLevel1) { 1058TEST_F(RegexTest, CombineLevel1) {
1052 expectTargetFcmVersion(1); 1059 expectTargetFcmVersion(1);
1053 auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */); 1060 auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */);
@@ -1212,6 +1219,77 @@ TEST_F(RegexTest, DeprecateLevel3) {
1212 } 1219 }
1213} 1220}
1214 1221
1222//
1223// Set of framework matrices of different FCM version with <kernel>.
1224//
1225
1226#define FAKE_KERNEL(__version__, __key__) \
1227 " <kernel version=\"" __version__ "\">\n" \
1228 " <config>\n" \
1229 " <key>CONFIG_" __key__ "</key>\n" \
1230 " <value type=\"tristate\">y</value>\n" \
1231 " </config>\n" \
1232 " </kernel>\n"
1233
1234const static std::vector<std::string> systemMatrixKernelXmls = {
1235 // 1.xml
1236 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
1237 FAKE_KERNEL("1.0.0", "A1")
1238 FAKE_KERNEL("2.0.0", "B1")
1239 "</compatibility-matrix>\n",
1240 // 2.xml
1241 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"2\">\n"
1242 FAKE_KERNEL("2.0.0", "B2")
1243 FAKE_KERNEL("3.0.0", "C2")
1244 FAKE_KERNEL("4.0.0", "D2")
1245 "</compatibility-matrix>\n",
1246 // 3.xml
1247 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"3\">\n"
1248 FAKE_KERNEL("4.0.0", "D3")
1249 FAKE_KERNEL("5.0.0", "E3")
1250 "</compatibility-matrix>\n",
1251};
1252
1253class KernelTest : public MultiMatrixTest {};
1254
1255// Assume that we are developing level 2. Test that old <kernel> requirements should
1256// not change and new <kernel> versions are added.
1257TEST_F(KernelTest, Level1AndLevel2) {
1258 SetUpMockSystemMatrices({systemMatrixKernelXmls[0], systemMatrixKernelXmls[1]});
1259
1260 expectTargetFcmVersion(1);
1261 auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */);
1262 ASSERT_NE(nullptr, matrix);
1263 std::string xml = gCompatibilityMatrixConverter(*matrix);
1264
1265 EXPECT_IN(FAKE_KERNEL("1.0.0", "A1"), xml) << "\nOld requirements must not change.";
1266 EXPECT_IN(FAKE_KERNEL("2.0.0", "B1"), xml) << "\nOld requirements must not change.";
1267 EXPECT_IN(FAKE_KERNEL("3.0.0", "C2"), xml) << "\nShould see <kernel> from new matrices";
1268 EXPECT_IN(FAKE_KERNEL("4.0.0", "D2"), xml) << "\nShould see <kernel> from new matrices";
1269
1270 EXPECT_NOT_IN(FAKE_KERNEL("2.0.0", "B2"), xml) << "\nOld requirements must not change";
1271}
1272
1273// Assume that we are developing level 3. Test that old <kernel> requirements should
1274// not change and new <kernel> versions are added.
1275TEST_F(KernelTest, Level1AndMore) {
1276 SetUpMockSystemMatrices({systemMatrixKernelXmls});
1277
1278 expectTargetFcmVersion(1);
1279 auto matrix = VintfObject::GetFrameworkCompatibilityMatrix(true /* skipCache */);
1280 ASSERT_NE(nullptr, matrix);
1281 std::string xml = gCompatibilityMatrixConverter(*matrix);
1282
1283 EXPECT_IN(FAKE_KERNEL("1.0.0", "A1"), xml) << "\nOld requirements must not change.";
1284 EXPECT_IN(FAKE_KERNEL("2.0.0", "B1"), xml) << "\nOld requirements must not change.";
1285 EXPECT_IN(FAKE_KERNEL("3.0.0", "C2"), xml) << "\nOld requirements must not change.";
1286 EXPECT_IN(FAKE_KERNEL("4.0.0", "D2"), xml) << "\nOld requirements must not change.";
1287 EXPECT_IN(FAKE_KERNEL("5.0.0", "E3"), xml) << "\nShould see <kernel> from new matrices";
1288
1289 EXPECT_NOT_IN(FAKE_KERNEL("2.0.0", "B2"), xml) << "\nOld requirements must not change";
1290 EXPECT_NOT_IN(FAKE_KERNEL("4.0.0", "D3"), xml) << "\nOld requirements must not change";
1291}
1292
1215int main(int argc, char** argv) { 1293int main(int argc, char** argv) {
1216 ::testing::InitGoogleMock(&argc, argv); 1294 ::testing::InitGoogleMock(&argc, argv);
1217 1295