summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYifan Hong2018-10-16 12:29:26 -0500
committerandroid-build-merger2018-10-16 12:29:26 -0500
commitdd4789a548ade3c7d6433784d9354c7e3e187824 (patch)
tree60ae6c3f1da9d7e2903d295649ddd6f77159bede
parent5fc1a4066dbaddf84b48ee6e34bc81d8b6ba2ae2 (diff)
parente7837b164cf04b95ddc1e365bda89d0422b925ad (diff)
downloadplatform-system-libvintf-dd4789a548ade3c7d6433784d9354c7e3e187824.tar.gz
platform-system-libvintf-dd4789a548ade3c7d6433784d9354c7e3e187824.tar.xz
platform-system-libvintf-dd4789a548ade3c7d6433784d9354c7e3e187824.zip
CompatibilityMatrix::combine() combines everything correctly
am: e7837b164c Change-Id: I0b3d6cbb68493152c127c0478575de778c2d2b4e
-rw-r--r--AssembleVintf.cpp52
-rw-r--r--CompatibilityMatrix.cpp312
-rw-r--r--VintfObject.cpp3
-rw-r--r--include/vintf/CompatibilityMatrix.h48
-rw-r--r--include/vintf/HalGroup.h2
-rw-r--r--include/vintf/MatrixKernel.h1
-rw-r--r--include/vintf/XmlFileGroup.h2
-rw-r--r--test/LibVintfTest.cpp5
8 files changed, 233 insertions, 192 deletions
diff --git a/AssembleVintf.cpp b/AssembleVintf.cpp
index 272301e..cc8db31 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -412,6 +412,7 @@ class AssembleVintfImpl : public AssembleVintf {
412 return true; 412 return true;
413 } 413 }
414 414
415 // Parse --kernel arguments and write to output matrix.
415 bool assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix* matrix) { 416 bool assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix* matrix) {
416 for (auto& pair : mKernels) { 417 for (auto& pair : mKernels) {
417 std::vector<ConditionedConfig> conditionedConfigs; 418 std::vector<ConditionedConfig> conditionedConfigs;
@@ -422,7 +423,11 @@ class AssembleVintfImpl : public AssembleVintf {
422 MatrixKernel kernel(KernelVersion{pair.first}, std::move(conditionedConfig.second)); 423 MatrixKernel kernel(KernelVersion{pair.first}, std::move(conditionedConfig.second));
423 if (conditionedConfig.first != nullptr) 424 if (conditionedConfig.first != nullptr)
424 kernel.mConditions.push_back(std::move(*conditionedConfig.first)); 425 kernel.mConditions.push_back(std::move(*conditionedConfig.first));
425 matrix->framework.mKernels.push_back(std::move(kernel)); 426 std::string error;
427 if (!matrix->addKernel(std::move(kernel), &error)) {
428 std::cerr << "Error:" << error << std::endl;
429 return false;
430 };
426 } 431 }
427 } 432 }
428 return true; 433 return true;
@@ -484,7 +489,24 @@ class AssembleVintfImpl : public AssembleVintf {
484 std::string error; 489 std::string error;
485 CompatibilityMatrix* matrix = nullptr; 490 CompatibilityMatrix* matrix = nullptr;
486 std::unique_ptr<HalManifest> checkManifest; 491 std::unique_ptr<HalManifest> checkManifest;
492 std::unique_ptr<CompatibilityMatrix> builtMatrix;
493
494 if (mCheckFile != nullptr) {
495 checkManifest = std::make_unique<HalManifest>();
496 if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile), &error)) {
497 std::cerr << "Cannot parse check file as a HAL manifest: " << error << std::endl;
498 return false;
499 }
500 }
501
487 if (matrices->front().object.mType == SchemaType::DEVICE) { 502 if (matrices->front().object.mType == SchemaType::DEVICE) {
503 if (matrices->size() > 1) {
504 std::cerr
505 << "assemble_vintf does not support merging device compatibilility matrices."
506 << std::endl;
507 return false;
508 }
509
488 matrix = &matrices->front().object; 510 matrix = &matrices->front().object;
489 511
490 auto vndkVersion = base::Trim(getEnv("REQUIRED_VNDK_VERSION")); 512 auto vndkVersion = base::Trim(getEnv("REQUIRED_VNDK_VERSION"));
@@ -506,24 +528,20 @@ class AssembleVintfImpl : public AssembleVintf {
506 } 528 }
507 529
508 if (matrices->front().object.mType == SchemaType::FRAMEWORK) { 530 if (matrices->front().object.mType == SchemaType::FRAMEWORK) {
509 Level deviceLevel = Level::UNSPECIFIED; 531 Level deviceLevel =
510 if (mCheckFile != nullptr) { 532 checkManifest != nullptr ? checkManifest->level() : Level::UNSPECIFIED;
511 checkManifest = std::make_unique<HalManifest>();
512 if (!gHalManifestConverter(checkManifest.get(), read(*mCheckFile), &error)) {
513 std::cerr << "Cannot parse check file as a HAL manifest: " << error
514 << std::endl;
515 return false;
516 }
517 deviceLevel = checkManifest->level();
518 }
519
520 if (deviceLevel == Level::UNSPECIFIED) { 533 if (deviceLevel == Level::UNSPECIFIED) {
521 // For GSI build, legacy devices that do not have a HAL manifest,
522 // and devices in development, merge all compatibility matrices.
523 deviceLevel = getLowestFcmVersion(*matrices); 534 deviceLevel = getLowestFcmVersion(*matrices);
535 if (checkManifest != nullptr && deviceLevel != Level::UNSPECIFIED) {
536 std::cerr << "Warning: No Target FCM Version for device. Assuming \""
537 << to_string(deviceLevel)
538 << "\" when building final framework compatibility matrix."
539 << std::endl;
540 }
524 } 541 }
542 builtMatrix = CompatibilityMatrix::combine(deviceLevel, matrices, &error);
543 matrix = builtMatrix.get();
525 544
526 matrix = CompatibilityMatrix::combine(deviceLevel, matrices, &error);
527 if (matrix == nullptr) { 545 if (matrix == nullptr) {
528 std::cerr << error << std::endl; 546 std::cerr << error << std::endl;
529 return false; 547 return false;
@@ -558,9 +576,9 @@ class AssembleVintfImpl : public AssembleVintf {
558 } 576 }
559 577
560 getFlagIfUnset("POLICYVERS", &matrix->framework.mSepolicy.mKernelSepolicyVersion, 578 getFlagIfUnset("POLICYVERS", &matrix->framework.mSepolicy.mKernelSepolicyVersion,
561 deviceLevel == Level::UNSPECIFIED /* log */); 579 false /* log */);
562 getFlagIfUnset("FRAMEWORK_VBMETA_VERSION", &matrix->framework.mAvbMetaVersion, 580 getFlagIfUnset("FRAMEWORK_VBMETA_VERSION", &matrix->framework.mAvbMetaVersion,
563 deviceLevel == Level::UNSPECIFIED /* log */); 581 false /* log */);
564 // Hard-override existing AVB version 582 // Hard-override existing AVB version
565 getFlag("FRAMEWORK_VBMETA_VERSION_OVERRIDE", &matrix->framework.mAvbMetaVersion, 583 getFlag("FRAMEWORK_VBMETA_VERSION_OVERRIDE", &matrix->framework.mAvbMetaVersion,
566 false /* log */); 584 false /* log */);
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 6a5645c..290ebf9 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -19,6 +19,8 @@
19#include <iostream> 19#include <iostream>
20#include <utility> 20#include <utility>
21 21
22#include <android-base/strings.h>
23
22#include "parse_string.h" 24#include "parse_string.h"
23#include "parse_xml.h" 25#include "parse_xml.h"
24#include "utils.h" 26#include "utils.h"
@@ -26,14 +28,59 @@
26namespace android { 28namespace android {
27namespace vintf { 29namespace vintf {
28 30
29bool CompatibilityMatrix::add(MatrixHal &&hal) { 31bool CompatibilityMatrix::addKernel(MatrixKernel&& kernel, std::string* error) {
30 return HalGroup<MatrixHal>::add(std::move(hal));
31}
32
33bool CompatibilityMatrix::add(MatrixKernel &&kernel) {
34 if (mType != SchemaType::FRAMEWORK) { 32 if (mType != SchemaType::FRAMEWORK) {
33 if (error) {
34 *error = "Cannot add <kernel> to a " + to_string(mType) + " compatibility matrix.";
35 }
35 return false; 36 return false;
36 } 37 }
38
39 auto it = framework.mKernels.begin();
40 for (; it != framework.mKernels.end(); ++it) {
41 if (it->minLts() == kernel.minLts()) {
42 break;
43 }
44 if (it->minLts().version == kernel.minLts().version &&
45 it->minLts().majorRev == kernel.minLts().majorRev) {
46 if (error) {
47 *error = "Kernel version mismatch; cannot add " + to_string(kernel.minLts()) +
48 " because " + to_string(it->minLts()) + " was added.";
49 }
50 return false;
51 }
52 }
53
54 bool seenVersion = it != framework.mKernels.end();
55
56 if (seenVersion) {
57 // If no conditions, must be the first among the same minLts
58 // because O libvintf only checks the first <kernel> tag that version matches.
59 if (kernel.conditions().empty()) {
60 // Found first <kernel> with the same minLts.
61 // Append config if it does not have <condition>s, else error.
62 if (it->conditions().empty()) {
63 const auto& configs = kernel.configs();
64 it->mConfigs.insert(it->mConfigs.end(), configs.begin(), configs.end());
65 } else {
66 if (error) {
67 *error =
68 "Base compatibility matrix has <condition> for the first <kernel> "
69 "with minlts " +
70 to_string(kernel.minLts()) + " for unknown reason.";
71 }
72 return false;
73 }
74 return true;
75 }
76 } else {
77 // First <kernel> of a minLts must not have <condition>'s for backwards compatibility
78 // with O libvintf.
79 if (!kernel.conditions().empty()) {
80 framework.mKernels.push_back(MatrixKernel(KernelVersion{kernel.minLts()}, {}));
81 }
82 }
83
37 framework.mKernels.push_back(std::move(kernel)); 84 framework.mKernels.push_back(std::move(kernel));
38 return true; 85 return true;
39} 86}
@@ -196,6 +243,27 @@ bool CompatibilityMatrix::addAllXmlFilesAsOptional(CompatibilityMatrix* other, s
196 return true; 243 return true;
197} 244}
198 245
246// Merge Kernel.
247// Add <kernel> from exact "level", then optionally add <kernel> from high levels to low levels.
248// For example, (each letter is a kernel version x.y.z)
249// 1.xml: A1, B1
250// 2.xml: B2, C2, D2
251// 3.xml: D3, E3
252// Then the combined 1.xml should have
253// A1, B1 (from 1.xml, required), C2, D2, E3 (optional, use earliest possible).
254bool CompatibilityMatrix::addAllKernels(CompatibilityMatrix* other, std::string* error) {
255 for (MatrixKernel& kernel : other->framework.mKernels) {
256 KernelVersion ver = kernel.minLts();
257 if (!addKernel(std::move(kernel), error)) {
258 if (error) {
259 *error = "Cannot add kernel version " + to_string(ver) + ": " + *error;
260 }
261 return false;
262 }
263 }
264 return true;
265}
266
199bool CompatibilityMatrix::addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error) { 267bool CompatibilityMatrix::addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error) {
200 if (other == nullptr || other->level() <= level()) { 268 if (other == nullptr || other->level() <= level()) {
201 return true; 269 return true;
@@ -216,9 +284,9 @@ bool CompatibilityMatrix::addAllKernelsAsOptional(CompatibilityMatrix* other, st
216 } 284 }
217 285
218 KernelVersion minLts = kernelToAdd.minLts(); 286 KernelVersion minLts = kernelToAdd.minLts();
219 if (!add(std::move(kernelToAdd))) { 287 if (!addKernel(std::move(kernelToAdd), error)) {
220 if (error) { 288 if (error) {
221 *error = "Cannot add " + to_string(minLts) + " for unknown reason."; 289 *error = "Cannot add " + to_string(minLts) + ": " + *error;
222 } 290 }
223 return false; 291 return false;
224 } 292 }
@@ -226,6 +294,34 @@ bool CompatibilityMatrix::addAllKernelsAsOptional(CompatibilityMatrix* other, st
226 return true; 294 return true;
227} 295}
228 296
297template <typename T>
298static bool mergeField(T* dst, T* src) {
299 static const T kEmpty{};
300 if (*dst == *src) {
301 return true; // no conflict
302 }
303 if (*src == kEmpty) {
304 return true;
305 }
306 if (*dst == kEmpty) {
307 *dst = std::move(*src);
308 return true;
309 }
310 return false;
311}
312
313bool CompatibilityMatrix::addSepolicy(CompatibilityMatrix* other, std::string* error) {
314 bool success = mergeField(&this->framework.mSepolicy, &other->framework.mSepolicy);
315 if (!success && error) *error = "<sepolicy> is already defined";
316 return success;
317}
318
319bool CompatibilityMatrix::addAvbMetaVersion(CompatibilityMatrix* other, std::string* error) {
320 bool success = mergeField(&this->framework.mAvbMetaVersion, &other->framework.mAvbMetaVersion);
321 if (!success && error) *error = "<avb><vbmeta-version> is already defined";
322 return success;
323}
324
229bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) { 325bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
230 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals && 326 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
231 lft.mXmlFiles == rgt.mXmlFiles && 327 lft.mXmlFiles == rgt.mXmlFiles &&
@@ -243,175 +339,83 @@ bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt)
243 lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion)); 339 lft.framework.mAvbMetaVersion == rgt.framework.mAvbMetaVersion));
244} 340}
245 341
246// Find compatibility_matrix.empty.xml (which has unspecified level) and use it 342std::unique_ptr<CompatibilityMatrix> CompatibilityMatrix::combine(
247// as a base matrix. 343 Level deviceLevel, std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) {
248CompatibilityMatrix* CompatibilityMatrix::findOrInsertBaseMatrix( 344 // Check type.
249 std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error) { 345 for (const auto& e : *matrices) {
250 std::vector<CompatibilityMatrix*> matricesUnspecified; 346 if (e.object.type() != SchemaType::FRAMEWORK) {
251 std::vector<CompatibilityMatrix*> matricesEmpty;
252 for (auto& e : *matrices) {
253 if (e.object.level() == Level::UNSPECIFIED) {
254 matricesUnspecified.push_back(&e.object);
255
256 if (!e.object.mHals.empty()) {
257 continue;
258 }
259
260 if (!e.object.mXmlFiles.empty()) {
261 continue;
262 }
263
264 matricesEmpty.push_back(&e.object);
265 }
266 }
267
268 if (matricesEmpty.size() > 1) {
269 if (error) {
270 *error =
271 "Error: multiple framework compatibility matrix files have "
272 "unspecified level; there should only be one such file.\n";
273 for (auto& e : *matrices) {
274 if (e.object.level() == Level::UNSPECIFIED) {
275 *error += " " + e.name + "\n";
276 }
277 }
278 }
279 return nullptr;
280 }
281 if (matricesEmpty.size() == 1) {
282 return matricesEmpty.front();
283 }
284 if (!matricesUnspecified.empty()) {
285 return matricesUnspecified.front();
286 }
287 auto matrix = &matrices->emplace(matrices->end())->object;
288 matrix->mType = SchemaType::FRAMEWORK;
289 matrix->mLevel = Level::UNSPECIFIED;
290 return matrix;
291}
292
293// Check if there are two files declaring level="1", for example, because
294// combine() use this assumption to simplify a lot of logic.
295static bool checkDuplicateLevels(const std::vector<Named<CompatibilityMatrix>>& matrices,
296 std::string* error) {
297 std::map<Level, const std::string*> existingLevels;
298 for (const auto& e : matrices) {
299 if (e.object.level() != Level::UNSPECIFIED &&
300 existingLevels.find(e.object.level()) != existingLevels.end()) {
301 if (error) { 347 if (error) {
302 *error = "Conflict of levels: file \"" + 348 *error = "File \"" + e.name + "\" is not a framework compatibility matrix.";
303 *existingLevels.find(e.object.level())->second + "\" and \"" + e.name + 349 return nullptr;
304 " both have level " + to_string(e.object.level());
305 } 350 }
306 return false;
307 } 351 }
308 existingLevels.emplace(e.object.level(), &e.name);
309 } 352 }
310 return true;
311}
312 353
313CompatibilityMatrix* CompatibilityMatrix::combine(Level deviceLevel, 354 // Matrices with unspecified (empty) level are auto-filled with deviceLevel.
314 std::vector<Named<CompatibilityMatrix>>* matrices, 355 for (auto& e : *matrices) {
315 std::string* error) { 356 if (e.object.level() == Level::UNSPECIFIED) {
316 if (!checkDuplicateLevels(*matrices, error)) { 357 e.object.mLevel = deviceLevel;
317 return nullptr; 358 }
318 } 359 }
319 360
320 CompatibilityMatrix* matrix = findOrInsertBaseMatrix(matrices, error); 361 // Add from low to high FCM version so that optional <kernel> requirements are added correctly.
321 if (matrix == nullptr) { 362 // See comment in addAllAsOptional.
322 return nullptr; 363 std::sort(matrices->begin(), matrices->end(),
323 } 364 [](const auto& x, const auto& y) { return x.object.level() < y.object.level(); });
324 365
325 matrix->mLevel = deviceLevel; 366 auto baseMatrix = std::make_unique<CompatibilityMatrix>();
367 baseMatrix->mLevel = deviceLevel;
368 baseMatrix->mType = SchemaType::FRAMEWORK;
326 369
370 std::vector<std::string> parsedFiles;
327 for (auto& e : *matrices) { 371 for (auto& e : *matrices) {
328 if (&e.object != matrix && 372 if (e.object.level() < deviceLevel) {
329 (e.object.level() == deviceLevel || e.object.level() == Level::UNSPECIFIED)) { 373 continue;
330 if (!matrix->addAllHals(&e.object, error)) {
331 if (error) {
332 *error = "File \"" + e.name + "\" cannot be added: HAL " + *error +
333 " has a conflict.";
334 }
335 return nullptr;
336 }
337
338 if (!matrix->addAllXmlFiles(&e.object, error)) {
339 if (error) {
340 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error +
341 " has a conflict.";
342 }
343 return nullptr;
344 }
345 } 374 }
346 }
347
348 for (auto& e : *matrices) {
349 if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED &&
350 e.object.level() > deviceLevel) {
351 if (!matrix->addAllHalsAsOptional(&e.object, error)) {
352 if (error) {
353 *error = "File \"" + e.name + "\" cannot be added: " + *error +
354 ". See <hal> with the same name " +
355 "in previously parsed files or previously declared in this file.";
356 }
357 return nullptr;
358 }
359 375
360 if (!matrix->addAllXmlFilesAsOptional(&e.object, error)) { 376 bool success = false;
361 if (error) { 377 if (e.object.level() == deviceLevel) {
362 *error = "File \"" + e.name + "\" cannot be added: XML File entry " + *error + 378 success = baseMatrix->addAll(&e, error);
363 " has a conflict."; 379 } else {
364 } 380 success = baseMatrix->addAllAsOptional(&e, error);
365 return nullptr;
366 }
367 } 381 }
368 } 382 if (!success) {
369 383 if (error) {
370 // Add <kernel> from exact "level", then optionally add <kernel> from high levels to low levels. 384 *error = "Conflict when merging \"" + e.name + "\": " + *error + "\n" +
371 // For example, (each letter is a kernel version x.y.z) 385 "Previous files:\n" + base::Join(parsedFiles, "\n");
372 // 1.xml: A1, B1
373 // 2.xml: B2, C2, D2
374 // 3.xml: D3, E3
375 // Then the combined 1.xml should have
376 // A1, B1 (from 1.xml, required), C2, D2, E3 (optional, use earliest possible).
377 for (auto& e : *matrices) {
378 if (&e.object != matrix && e.object.level() == deviceLevel &&
379 e.object.type() == SchemaType::FRAMEWORK) {
380 for (MatrixKernel& kernel : e.object.framework.mKernels) {
381 KernelVersion ver = kernel.minLts();
382 if (!matrix->add(std::move(kernel))) {
383 if (error) {
384 *error = "Cannot add kernel version " + to_string(ver) +
385 " from FCM version " + to_string(deviceLevel);
386 }
387 return nullptr;
388 }
389 } 386 }
387 return nullptr;
390 } 388 }
389 parsedFiles.push_back(e.name);
391 } 390 }
392 391
393 // There is only one file per level, hence a map is used instead of a multimap. Also, there is 392 return baseMatrix;
394 // no good ordering (i.e. priority) for multiple files with the same level. 393}
395 std::map<Level, Named<CompatibilityMatrix>*> matricesMap; 394
396 for (auto& e : *matrices) { 395bool CompatibilityMatrix::addAll(Named<CompatibilityMatrix>* inputMatrix, std::string* error) {
397 if (&e.object != matrix && e.object.level() != Level::UNSPECIFIED && 396 if (!addAllHals(&inputMatrix->object, error) || !addAllXmlFiles(&inputMatrix->object, error) ||
398 e.object.level() > deviceLevel && e.object.type() == SchemaType::FRAMEWORK) { 397 !addAllKernels(&inputMatrix->object, error) || !addSepolicy(&inputMatrix->object, error) ||
399 matricesMap.emplace(e.object.level(), &e); 398 !addAvbMetaVersion(&inputMatrix->object, error)) {
399 if (error) {
400 *error = "File \"" + inputMatrix->name + "\" cannot be added: " + *error + ".";
400 } 401 }
401 } 402 }
403 return true;
404}
402 405
403 for (auto&& pair : matricesMap) { 406bool CompatibilityMatrix::addAllAsOptional(Named<CompatibilityMatrix>* inputMatrix,
404 if (!matrix->addAllKernelsAsOptional(&pair.second->object, error)) { 407 std::string* error) {
405 if (error) { 408 if (!addAllHalsAsOptional(&inputMatrix->object, error) ||
406 *error = "Cannot add new kernel versions from FCM version " + 409 !addAllXmlFilesAsOptional(&inputMatrix->object, error) ||
407 to_string(pair.first) + " (" + pair.second->name + ")" + 410 !addAllKernelsAsOptional(&inputMatrix->object, error)) {
408 " to FCM version " + to_string(deviceLevel) + ": " + *error; 411 if (error) {
409 } 412 *error = "File \"" + inputMatrix->name + "\" cannot be added: " + *error;
410 return nullptr;
411 } 413 }
414 return false;
412 } 415 }
413 416 // ignore <sepolicy> requirement from higher level
414 return matrix; 417 // ignore <avb> requirement from higher level
418 return true;
415} 419}
416 420
417bool CompatibilityMatrix::forEachInstanceOfVersion( 421bool CompatibilityMatrix::forEachInstanceOfVersion(
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 1086590..aed9745 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -196,8 +196,7 @@ status_t VintfObject::getCombinedFrameworkMatrix(
196 return NAME_NOT_FOUND; 196 return NAME_NOT_FOUND;
197 } 197 }
198 198
199 CompatibilityMatrix* combined = 199 auto combined = CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error);
200 CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error);
201 if (combined == nullptr) { 200 if (combined == nullptr) {
202 return BAD_VALUE; 201 return BAD_VALUE;
203 } 202 }
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 512d278..feb8ac8 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -18,6 +18,7 @@
18#define ANDROID_VINTF_COMPATIBILITY_MATRIX_H 18#define ANDROID_VINTF_COMPATIBILITY_MATRIX_H
19 19
20#include <map> 20#include <map>
21#include <memory>
21#include <string> 22#include <string>
22 23
23#include <utils/Errors.h> 24#include <utils/Errors.h>
@@ -67,8 +68,23 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat
67 std::string getVendorNdkVersion() const; 68 std::string getVendorNdkVersion() const;
68 69
69 private: 70 private:
70 bool add(MatrixHal &&hal); 71 // Add everything in inputMatrix to "this" as requirements.
71 bool add(MatrixKernel &&kernel); 72 bool addAll(Named<CompatibilityMatrix>* inputMatrix, std::string* error);
73
74 // Add all <kernel> from other to "this". Error if there is a conflict.
75 bool addAllKernels(CompatibilityMatrix* other, std::string* error);
76
77 // Add a <kernel> tag to "this". Error if there is a conflict.
78 bool addKernel(MatrixKernel&& kernel, std::string* error);
79
80 // Merge <sepolicy> with other's <sepolicy>. Error if there is a conflict.
81 bool addSepolicy(CompatibilityMatrix* other, std::string* error);
82
83 // Merge <avb><vbmeta-version> with other's <avb><vbmeta-version>. Error if there is a conflict.
84 bool addAvbMetaVersion(CompatibilityMatrix* other, std::string* error);
85
86 // Add everything in inputMatrix to "this" as optional.
87 bool addAllAsOptional(Named<CompatibilityMatrix>* inputMatrix, std::string* error);
72 88
73 // Add all HALs as optional HALs from "other". This function moves MatrixHal objects 89 // Add all HALs as optional HALs from "other". This function moves MatrixHal objects
74 // from "other". 90 // from "other".
@@ -81,23 +97,23 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat
81 // Similar to addAllHalsAsOptional but on <kernel> entries. 97 // Similar to addAllHalsAsOptional but on <kernel> entries.
82 bool addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error); 98 bool addAllKernelsAsOptional(CompatibilityMatrix* other, std::string* error);
83 99
100 // Combine a set of framework compatibility matrices. For each CompatibilityMatrix in matrices
101 // (in the order of level(), where UNSPECIFIED (empty) is treated as deviceLevel)
102 // - If level() < deviceLevel, ignore
103 // - If level() == UNSPECIFIED or level() == deviceLevel,
104 // - Add as hard requirements. See combineSameFcmVersion
105 // - If level() > deviceLevel,
106 // - all <hal> versions and <xmlfile>s are added as optional.
107 // - <kernel minlts="x.y.z"> is added only if x.y does not exist in a file
108 // with lower level()
109 // - <sepolicy>, <avb><vbmeta-version> is ignored
110 // Return the combined matrix, nullptr if any error (e.g. conflict of information).
111 static std::unique_ptr<CompatibilityMatrix> combine(
112 Level deviceLevel, std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error);
113
84 status_t fetchAllInformation(const FileSystem* fileSystem, const std::string& path, 114 status_t fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
85 std::string* error = nullptr); 115 std::string* error = nullptr);
86 116
87 // Combine a subset of "matrices". For each CompatibilityMatrix in matrices,
88 // - If level() == UNSPECIFIED, use it as the base matrix (for non-HAL, non-XML-file
89 // requirements).
90 // - If level() < deviceLevel, ignore
91 // - If level() == deviceLevel, all HAL versions and XML files are added as is
92 // (optionality is kept)
93 // - If level() > deviceLevel, all HAL versions and XML files are added as optional.
94 // Return a pointer into one of the elements in "matrices".
95 static CompatibilityMatrix* combine(Level deviceLevel,
96 std::vector<Named<CompatibilityMatrix>>* matrices,
97 std::string* error);
98 static CompatibilityMatrix* findOrInsertBaseMatrix(
99 std::vector<Named<CompatibilityMatrix>>* matrices, std::string* error);
100
101 MatrixHal* splitInstance(MatrixHal* existingHal, const std::string& interface, 117 MatrixHal* splitInstance(MatrixHal* existingHal, const std::string& interface,
102 const std::string& instance, bool isRegex); 118 const std::string& instance, bool isRegex);
103 119
diff --git a/include/vintf/HalGroup.h b/include/vintf/HalGroup.h
index a0a14cd..5cad867 100644
--- a/include/vintf/HalGroup.h
+++ b/include/vintf/HalGroup.h
@@ -39,7 +39,7 @@ struct HalGroup {
39 for (auto& pair : other->mHals) { 39 for (auto& pair : other->mHals) {
40 if (!add(std::move(pair.second))) { 40 if (!add(std::move(pair.second))) {
41 if (error) { 41 if (error) {
42 *error = pair.first; 42 *error = "HAL \"" + pair.first + "\" has a conflict.";
43 } 43 }
44 return false; 44 return false;
45 } 45 }
diff --git a/include/vintf/MatrixKernel.h b/include/vintf/MatrixKernel.h
index cee7e32..14cf5bf 100644
--- a/include/vintf/MatrixKernel.h
+++ b/include/vintf/MatrixKernel.h
@@ -58,6 +58,7 @@ struct MatrixKernel {
58 private: 58 private:
59 friend struct MatrixKernelConverter; 59 friend struct MatrixKernelConverter;
60 friend struct MatrixKernelConditionsConverter; 60 friend struct MatrixKernelConditionsConverter;
61 friend struct CompatibilityMatrix;
61 friend class AssembleVintfImpl; 62 friend class AssembleVintfImpl;
62 63
63 KernelVersion mMinLts; 64 KernelVersion mMinLts;
diff --git a/include/vintf/XmlFileGroup.h b/include/vintf/XmlFileGroup.h
index 524efc9..dd15647 100644
--- a/include/vintf/XmlFileGroup.h
+++ b/include/vintf/XmlFileGroup.h
@@ -62,7 +62,7 @@ struct XmlFileGroup {
62 for (auto& pair : other->mXmlFiles) { 62 for (auto& pair : other->mXmlFiles) {
63 if (!addXmlFile(std::move(pair.second))) { 63 if (!addXmlFile(std::move(pair.second))) {
64 if (error) { 64 if (error) {
65 *error = pair.first; 65 *error = "XML File \"" + pair.first + "\" has a conflict.";
66 } 66 }
67 return false; 67 return false;
68 } 68 }
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index 68af9bb..a3a98b8 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -59,7 +59,10 @@ public:
59 return cm.add(std::move(hal)); 59 return cm.add(std::move(hal));
60 } 60 }
61 bool add(CompatibilityMatrix &cm, MatrixKernel &&kernel) { 61 bool add(CompatibilityMatrix &cm, MatrixKernel &&kernel) {
62 return cm.add(std::move(kernel)); 62 std::string error;
63 bool success = cm.addKernel(std::move(kernel), &error);
64 EXPECT_EQ(success, error == "") << "success: " << success << ", error: " << error;
65 return success;
63 } 66 }
64 bool add(HalManifest &vm, ManifestHal &&hal) { 67 bool add(HalManifest &vm, ManifestHal &&hal) {
65 return vm.add(std::move(hal)); 68 return vm.add(std::move(hal));