summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandroid-build-team Robot2017-12-14 02:32:23 -0600
committerandroid-build-team Robot2017-12-14 02:32:23 -0600
commitfeaa8b9897871565146ff0b82a7ed03627cf25ae (patch)
tree94e578c5fc292b9a09afd77dcad11102919ea106
parenta4edc386e298638274024c8442d8b9969b04fffe (diff)
parent7b2970a4b9ba571c773e23226e37f77c7192de00 (diff)
downloadplatform-system-libvintf-feaa8b9897871565146ff0b82a7ed03627cf25ae.tar.gz
platform-system-libvintf-feaa8b9897871565146ff0b82a7ed03627cf25ae.tar.xz
platform-system-libvintf-feaa8b9897871565146ff0b82a7ed03627cf25ae.zip
Snap for 4502278 from 7b2970a4b9ba571c773e23226e37f77c7192de00 to pi-release
Change-Id: I081dee4666c761af18d2f7b985ca7ce05cbb8f0f
-rw-r--r--Android.bp2
-rw-r--r--CompatibilityMatrix.cpp66
-rw-r--r--HalManifest.cpp7
-rw-r--r--MatrixHal.cpp18
-rw-r--r--assemble_vintf.cpp274
-rw-r--r--include/vintf/CompatibilityMatrix.h13
-rw-r--r--include/vintf/HalManifest.h5
-rw-r--r--include/vintf/Level.h44
-rw-r--r--include/vintf/MatrixHal.h3
-rw-r--r--include/vintf/parse_string.h2
-rw-r--r--include/vintf/parse_xml.h17
-rw-r--r--parse_string.cpp27
-rw-r--r--parse_xml.cpp76
-rw-r--r--test/Android.bp4
-rw-r--r--test/main.cpp185
15 files changed, 680 insertions, 63 deletions
diff --git a/Android.bp b/Android.bp
index c47c0e7..2fd9eef 100644
--- a/Android.bp
+++ b/Android.bp
@@ -117,7 +117,7 @@ cc_binary_host {
117 ], 117 ],
118} 118}
119 119
120cc_library { 120cc_library_static {
121 name: "libvintftest", 121 name: "libvintftest",
122 defaults: ["libvintf-defaults"], 122 defaults: ["libvintf-defaults"],
123 host_supported: true, 123 host_supported: true,
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 73d0384..521c44b 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -16,6 +16,8 @@
16 16
17#include "CompatibilityMatrix.h" 17#include "CompatibilityMatrix.h"
18 18
19#include <utility>
20
19#include "parse_string.h" 21#include "parse_string.h"
20#include "utils.h" 22#include "utils.h"
21 23
@@ -38,6 +40,10 @@ SchemaType CompatibilityMatrix::type() const {
38 return mType; 40 return mType;
39} 41}
40 42
43Level CompatibilityMatrix::level() const {
44 return mLevel;
45}
46
41Version CompatibilityMatrix::getMinimumMetaVersion() const { 47Version CompatibilityMatrix::getMinimumMetaVersion() const {
42 // TODO(b/62801658): this needs to depend on whether there are 1.1 requirements 48 // TODO(b/62801658): this needs to depend on whether there are 1.1 requirements
43 // (e.g. required <xmlfile> entry) 49 // (e.g. required <xmlfile> entry)
@@ -67,8 +73,66 @@ std::string CompatibilityMatrix::getXmlSchemaPath(const std::string& xmlFileName
67 return ""; 73 return "";
68} 74}
69 75
76static VersionRange* findRangeWithMajorVersion(std::vector<VersionRange>& versionRanges,
77 size_t majorVer) {
78 for (VersionRange& vr : versionRanges) {
79 if (vr.majorVer == majorVer) {
80 return &vr;
81 }
82 }
83 return nullptr;
84}
85
86std::pair<MatrixHal*, VersionRange*> CompatibilityMatrix::getHalWithMajorVersion(
87 const std::string& name, size_t majorVer) {
88 for (MatrixHal* hal : getHals(name)) {
89 VersionRange* vr = findRangeWithMajorVersion(hal->versionRanges, majorVer);
90 if (vr != nullptr) {
91 return {hal, vr};
92 }
93 }
94 return {nullptr, nullptr};
95}
96
97bool CompatibilityMatrix::addAllHalsAsOptional(CompatibilityMatrix* other, std::string* error) {
98 if (other == nullptr || other->level() <= level()) {
99 return true;
100 }
101
102 for (auto& pair : other->mHals) {
103 const std::string& name = pair.first;
104 MatrixHal& halToAdd = pair.second;
105 for (const VersionRange& vr : halToAdd.versionRanges) {
106 MatrixHal* existingHal;
107 VersionRange* existingVr;
108 std::tie(existingHal, existingVr) = getHalWithMajorVersion(name, vr.majorVer);
109
110 if (existingHal == nullptr) {
111 halToAdd.optional = true;
112 add(std::move(halToAdd));
113 continue;
114 }
115
116 if (!existingHal->optional && !existingHal->containsInstances(halToAdd)) {
117 if (error != nullptr) {
118 *error = "HAL " + name + "@" + to_string(vr.minVer()) + " is a required " +
119 "HAL, but fully qualified instance names don't match (at FCM "
120 "Version " +
121 std::to_string(level()) + " and " + std::to_string(other->level()) +
122 ")";
123 }
124 return false;
125 }
126
127 existingVr->maxMinor = std::max(existingVr->maxMinor, vr.maxMinor);
128 }
129 }
130 return true;
131}
132
70bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) { 133bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
71 return lft.mType == rgt.mType && lft.mHals == rgt.mHals && lft.mXmlFiles == rgt.mXmlFiles && 134 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
135 lft.mXmlFiles == rgt.mXmlFiles &&
72 (lft.mType != SchemaType::DEVICE || (lft.device.mVndk == rgt.device.mVndk)) && 136 (lft.mType != SchemaType::DEVICE || (lft.device.mVndk == rgt.device.mVndk)) &&
73 (lft.mType != SchemaType::FRAMEWORK || 137 (lft.mType != SchemaType::FRAMEWORK ||
74 (lft.framework.mKernels == rgt.framework.mKernels && 138 (lft.framework.mKernels == rgt.framework.mKernels &&
diff --git a/HalManifest.cpp b/HalManifest.cpp
index c633a7a..9683729 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -319,6 +319,10 @@ SchemaType HalManifest::type() const {
319 return mType; 319 return mType;
320} 320}
321 321
322Level HalManifest::level() const {
323 return mLevel;
324}
325
322Version HalManifest::getMetaVersion() const { 326Version HalManifest::getMetaVersion() const {
323 return mMetaVersion; 327 return mMetaVersion;
324} 328}
@@ -352,7 +356,8 @@ std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
352} 356}
353 357
354bool operator==(const HalManifest &lft, const HalManifest &rgt) { 358bool operator==(const HalManifest &lft, const HalManifest &rgt) {
355 return lft.mType == rgt.mType && lft.mHals == rgt.mHals && lft.mXmlFiles == rgt.mXmlFiles && 359 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
360 lft.mXmlFiles == rgt.mXmlFiles &&
356 (lft.mType != SchemaType::DEVICE || 361 (lft.mType != SchemaType::DEVICE ||
357 (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) && 362 (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) &&
358 (lft.mType != SchemaType::FRAMEWORK || (lft.framework.mVndks == rgt.framework.mVndks)); 363 (lft.mType != SchemaType::FRAMEWORK || (lft.framework.mVndks == rgt.framework.mVndks));
diff --git a/MatrixHal.cpp b/MatrixHal.cpp
index 50c5116..96dcf78 100644
--- a/MatrixHal.cpp
+++ b/MatrixHal.cpp
@@ -48,5 +48,23 @@ std::set<std::string> MatrixHal::getInstances(const std::string& interfaceName)
48 return ret; 48 return ret;
49} 49}
50 50
51bool MatrixHal::containsInstances(const MatrixHal& other) const {
52 for (const auto& pair : other.interfaces) {
53 const std::string& interfaceName = pair.first;
54 auto thisIt = interfaces.find(interfaceName);
55 if (thisIt == interfaces.end()) {
56 return false;
57 }
58
59 const std::set<std::string>& thisInstances = thisIt->second.instances;
60 const std::set<std::string>& otherInstances = pair.second.instances;
61 if (!std::includes(thisInstances.begin(), thisInstances.end(), otherInstances.begin(),
62 otherInstances.end())) {
63 return false;
64 }
65 }
66 return true;
67}
68
51} // namespace vintf 69} // namespace vintf
52} // namespace android 70} // namespace android
diff --git a/assemble_vintf.cpp b/assemble_vintf.cpp
index 8874f69..19294c6 100644
--- a/assemble_vintf.cpp
+++ b/assemble_vintf.cpp
@@ -25,6 +25,7 @@
25#include <string> 25#include <string>
26 26
27#include <android-base/file.h> 27#include <android-base/file.h>
28#include <android-base/parseint.h>
28 29
29#include <vintf/KernelConfigParser.h> 30#include <vintf/KernelConfigParser.h>
30#include <vintf/parse_string.h> 31#include <vintf/parse_string.h>
@@ -63,6 +64,24 @@ class AssembleVintf {
63 return true; 64 return true;
64 } 65 }
65 66
67 static bool getBooleanFlag(const char* key) {
68 const char* envValue = getenv(key);
69 return envValue != nullptr && strcmp(envValue, "true") == 0;
70 }
71
72 static size_t getIntegerFlag(const char* key, size_t defaultValue = 0) {
73 std::string envValue = getenv(key);
74 if (envValue.empty()) {
75 return defaultValue;
76 }
77 size_t value;
78 if (!base::ParseUint(envValue, &value)) {
79 std::cerr << "Error: " << key << " must be a number." << std::endl;
80 return defaultValue;
81 }
82 return value;
83 }
84
66 static std::string read(std::basic_istream<char>& is) { 85 static std::string read(std::basic_istream<char>& is) {
67 std::stringstream ss; 86 std::stringstream ss;
68 ss << is.rdbuf(); 87 ss << is.rdbuf();
@@ -73,6 +92,18 @@ class AssembleVintf {
73 return ::android::base::Basename(path) == gBaseConfig; 92 return ::android::base::Basename(path) == gBaseConfig;
74 } 93 }
75 94
95 static Level convertFromApiLevel(size_t apiLevel) {
96 if (apiLevel < 26) {
97 return Level::LEGACY;
98 } else if (apiLevel == 26) {
99 return Level::O;
100 } else if (apiLevel == 27) {
101 return Level::O_MR1;
102 } else {
103 return Level::UNSPECIFIED;
104 }
105 }
106
76 // nullptr on any error, otherwise the condition. 107 // nullptr on any error, otherwise the condition.
77 static Condition generateCondition(const std::string& path) { 108 static Condition generateCondition(const std::string& path) {
78 std::string fname = ::android::base::Basename(path); 109 std::string fname = ::android::base::Basename(path);
@@ -173,17 +204,59 @@ class AssembleVintf {
173 return ret; 204 return ret;
174 } 205 }
175 206
207 static std::string getFileNameFromPath(std::string path) {
208 auto idx = path.find_last_of("\\/");
209 if (idx != std::string::npos) {
210 path.erase(0, idx + 1);
211 }
212 return path;
213 }
214
176 std::basic_ostream<char>& out() const { 215 std::basic_ostream<char>& out() const {
177 return mOutFileRef == nullptr ? std::cout : *mOutFileRef; 216 return mOutFileRef == nullptr ? std::cout : *mOutFileRef;
178 } 217 }
179 218
180 bool assembleHalManifest(HalManifest* halManifest) { 219 template <typename S>
220 using Schemas = std::vector<std::pair<std::string, S>>;
221 using HalManifests = Schemas<HalManifest>;
222 using CompatibilityMatrices = Schemas<CompatibilityMatrix>;
223
224 bool assembleHalManifest(HalManifests* halManifests) {
181 std::string error; 225 std::string error;
226 HalManifest* halManifest = &halManifests->front().second;
227 for (auto it = halManifests->begin() + 1; it != halManifests->end(); ++it) {
228 const std::string& path = it->first;
229 HalManifest& halToAdd = it->second;
230
231 if (halToAdd.level() != Level::UNSPECIFIED) {
232 if (halManifest->level() == Level::UNSPECIFIED) {
233 halManifest->mLevel = halToAdd.level();
234 } else if (halManifest->level() != halToAdd.level()) {
235 std::cerr << "Inconsistent FCM Version in HAL manifests:" << std::endl
236 << " File '" << halManifests->front().first << "' has level "
237 << halManifest->level() << std::endl
238 << " File '" << path << "' has level " << halToAdd.level()
239 << std::endl;
240 return false;
241 }
242 }
243
244 if (!halManifest->addAll(std::move(halToAdd), &error)) {
245 std::cerr << "File \"" << path << "\" cannot be added: conflict on HAL \"" << error
246 << "\" with an existing HAL. See <hal> with the same name "
247 << "in previously parsed files or previously declared in this file."
248 << std::endl;
249 return false;
250 }
251 }
182 252
183 if (halManifest->mType == SchemaType::DEVICE) { 253 if (halManifest->mType == SchemaType::DEVICE) {
184 if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) { 254 if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) {
185 return false; 255 return false;
186 } 256 }
257 if (!setDeviceFcmVersion(halManifest)) {
258 return false;
259 }
187 } 260 }
188 261
189 if (mOutputMatrix) { 262 if (mOutputMatrix) {
@@ -199,9 +272,9 @@ class AssembleVintf {
199 " Many entries other than HALs are zero-filled and\n" 272 " Many entries other than HALs are zero-filled and\n"
200 " require human attention. \n" 273 " require human attention. \n"
201 "-->\n" 274 "-->\n"
202 << gCompatibilityMatrixConverter(generatedMatrix); 275 << gCompatibilityMatrixConverter(generatedMatrix, mSerializeFlags);
203 } else { 276 } else {
204 out() << gHalManifestConverter(*halManifest); 277 out() << gHalManifestConverter(*halManifest, mSerializeFlags);
205 } 278 }
206 out().flush(); 279 out().flush();
207 280
@@ -248,12 +321,107 @@ class AssembleVintf {
248 return true; 321 return true;
249 } 322 }
250 323
251 bool assembleCompatibilityMatrix(CompatibilityMatrix* matrix) { 324 bool setDeviceFcmVersion(HalManifest* manifest) {
252 std::string error; 325 size_t shippingApiLevel = getIntegerFlag("PRODUCT_SHIPPING_API_LEVEL");
253 326
327 if (manifest->level() != Level::UNSPECIFIED) {
328 return true;
329 }
330 if (!getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST")) {
331 manifest->mLevel = Level::LEGACY;
332 return true;
333 }
334 // TODO(b/70628538): Do not infer from Shipping API level.
335 if (shippingApiLevel) {
336 std::cerr << "Warning: Shipping FCM Version is inferred from Shipping API level. "
337 << "Declare Shipping FCM Version in device manifest directly." << std::endl;
338 manifest->mLevel = convertFromApiLevel(shippingApiLevel);
339 if (manifest->mLevel == Level::UNSPECIFIED) {
340 std::cerr << "Error: Shipping FCM Version cannot be inferred from Shipping API "
341 << "level " << shippingApiLevel << "."
342 << "Declare Shipping FCM Version in device manifest directly."
343 << std::endl;
344 return false;
345 }
346 return true;
347 }
348 // TODO(b/69638851): should be an error if Shipping API level is not defined.
349 // For now, just leave it empty; when framework compatibility matrix is built,
350 // lowest FCM Version is assumed.
351 std::cerr << "Warning: Shipping FCM Version cannot be inferred, because:" << std::endl
352 << " (1) It is not explicitly declared in device manifest;" << std::endl
353 << " (2) PRODUCT_ENFORCE_VINTF_MANIFEST is set to true;" << std::endl
354 << " (3) PRODUCT_SHIPPING_API_LEVEL is undefined." << std::endl
355 << "Assuming 'unspecified' Shipping FCM Version. " << std::endl
356 << "To remove this warning, define 'level' attribute in device manifest."
357 << std::endl;
358 return true;
359 }
360
361 Level getLowestFcmVersion(const CompatibilityMatrices& matrices) {
362 Level ret = Level::UNSPECIFIED;
363 for (const auto& e : matrices) {
364 if (ret == Level::UNSPECIFIED || ret > e.second.level()) {
365 ret = e.second.level();
366 }
367 }
368 return ret;
369 }
370
371 bool assembleCompatibilityMatrix(CompatibilityMatrices* matrices) {
372 std::string error;
373 CompatibilityMatrix* matrix = nullptr;
254 KernelSepolicyVersion kernelSepolicyVers; 374 KernelSepolicyVersion kernelSepolicyVers;
255 Version sepolicyVers; 375 Version sepolicyVers;
256 if (matrix->mType == SchemaType::FRAMEWORK) { 376 std::unique_ptr<HalManifest> checkManifest;
377 if (matrices->front().second.mType == SchemaType::DEVICE) {
378 matrix = &matrices->front().second;
379 }
380
381 if (matrices->front().second.mType == SchemaType::FRAMEWORK) {
382 Level deviceLevel = Level::UNSPECIFIED;
383 std::vector<std::string> fileList;
384 if (mCheckFile.is_open()) {
385 checkManifest = std::make_unique<HalManifest>();
386 if (!gHalManifestConverter(checkManifest.get(), read(mCheckFile))) {
387 std::cerr << "Cannot parse check file as a HAL manifest: "
388 << gHalManifestConverter.lastError() << std::endl;
389 return false;
390 }
391 deviceLevel = checkManifest->level();
392 }
393
394 if (deviceLevel == Level::UNSPECIFIED) {
395 // For GSI build, legacy devices that do not have a HAL manifest,
396 // and devices in development, merge all compatibility matrices.
397 deviceLevel = getLowestFcmVersion(*matrices);
398 }
399
400 for (auto& e : *matrices) {
401 if (e.second.level() == deviceLevel) {
402 fileList.push_back(e.first);
403 matrix = &e.second;
404 }
405 }
406 if (matrix == nullptr) {
407 std::cerr << "FATAL ERROR: cannot find matrix with level '" << deviceLevel << "'"
408 << std::endl;
409 return false;
410 }
411 for (auto& e : *matrices) {
412 if (e.second.level() <= deviceLevel) {
413 continue;
414 }
415 fileList.push_back(e.first);
416 if (!matrix->addAllHalsAsOptional(&e.second, &error)) {
417 std::cerr << "File \"" << e.first << "\" cannot be added: " << error
418 << ". See <hal> with the same name "
419 << "in previously parsed files or previously declared in this file."
420 << std::endl;
421 return false;
422 }
423 }
424
257 if (!getFlag("BOARD_SEPOLICY_VERS", &sepolicyVers)) { 425 if (!getFlag("BOARD_SEPOLICY_VERS", &sepolicyVers)) {
258 return false; 426 return false;
259 } 427 }
@@ -273,21 +441,21 @@ class AssembleVintf {
273 return false; 441 return false;
274 } 442 }
275 matrix->framework.mAvbMetaVersion = avbMetaVersion; 443 matrix->framework.mAvbMetaVersion = avbMetaVersion;
444
445 out() << "<!--" << std::endl;
446 out() << " Input:" << std::endl;
447 for (const auto& path : fileList) {
448 out() << " " << getFileNameFromPath(path) << std::endl;
449 }
450 out() << "-->" << std::endl;
276 } 451 }
277 out() << gCompatibilityMatrixConverter(*matrix); 452 out() << gCompatibilityMatrixConverter(*matrix, mSerializeFlags);
278 out().flush(); 453 out().flush();
279 454
280 if (mCheckFile.is_open()) { 455 if (checkManifest != nullptr && getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST") &&
281 HalManifest checkManifest; 456 !checkManifest->checkCompatibility(*matrix, &error)) {
282 if (!gHalManifestConverter(&checkManifest, read(mCheckFile))) { 457 std::cerr << "Not compatible: " << error << std::endl;
283 std::cerr << "Cannot parse check file as a HAL manifest: " 458 return false;
284 << gHalManifestConverter.lastError() << std::endl;
285 return false;
286 }
287 if (!checkManifest.checkCompatibility(*matrix, &error)) {
288 std::cerr << "Not compatible: " << error << std::endl;
289 return false;
290 }
291 } 459 }
292 460
293 return true; 461 return true;
@@ -297,38 +465,33 @@ class AssembleVintf {
297 template <typename Schema, typename AssembleFunc> 465 template <typename Schema, typename AssembleFunc>
298 AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName, 466 AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName,
299 AssembleFunc assemble) { 467 AssembleFunc assemble) {
468 Schemas<Schema> schemas;
300 Schema schema; 469 Schema schema;
301 if (!converter(&schema, read(mInFiles.front()))) { 470 if (!converter(&schema, read(mInFiles.front()))) {
302 return TRY_NEXT; 471 return TRY_NEXT;
303 } 472 }
304 auto firstType = schema.type(); 473 auto firstType = schema.type();
474 schemas.emplace_back(mInFilePaths.front(), std::move(schema));
475
305 for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) { 476 for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) {
306 Schema additionalSchema; 477 Schema additionalSchema;
478 const std::string fileName = mInFilePaths[std::distance(mInFiles.begin(), it)];
307 if (!converter(&additionalSchema, read(*it))) { 479 if (!converter(&additionalSchema, read(*it))) {
308 std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)] 480 std::cerr << "File \"" << fileName << "\" is not a valid " << firstType << " "
309 << "\" is not a valid " << firstType << " " << schemaName 481 << schemaName << " (but the first file is a valid " << firstType << " "
310 << " (but the first file is a valid " << firstType << " " << schemaName 482 << schemaName << "). Error: " << converter.lastError() << std::endl;
311 << "). Error: " << converter.lastError() << std::endl;
312 return FAIL_AND_EXIT; 483 return FAIL_AND_EXIT;
313 } 484 }
314 if (additionalSchema.type() != firstType) { 485 if (additionalSchema.type() != firstType) {
315 std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)] 486 std::cerr << "File \"" << fileName << "\" is a " << additionalSchema.type() << " "
316 << "\" is a " << additionalSchema.type() << " " << schemaName 487 << schemaName << " (but a " << firstType << " " << schemaName
317 << " (but a " << firstType << " " << schemaName << " is expected)." 488 << " is expected)." << std::endl;
318 << std::endl;
319 return FAIL_AND_EXIT;
320 }
321 std::string error;
322 if (!schema.addAll(std::move(additionalSchema), &error)) {
323 std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)]
324 << "\" cannot be added: conflict on HAL \"" << error
325 << "\" with an existing HAL. See <hal> with the same name "
326 << "in previously parsed files or previously declared in this file."
327 << std::endl;
328 return FAIL_AND_EXIT; 489 return FAIL_AND_EXIT;
329 } 490 }
491
492 schemas.emplace_back(fileName, std::move(additionalSchema));
330 } 493 }
331 return assemble(&schema) ? SUCCESS : FAIL_AND_EXIT; 494 return assemble(&schemas) ? SUCCESS : FAIL_AND_EXIT;
332 } 495 }
333 496
334 bool assemble() { 497 bool assemble() {
@@ -385,6 +548,18 @@ class AssembleVintf {
385 548
386 void setOutputMatrix() { mOutputMatrix = true; } 549 void setOutputMatrix() { mOutputMatrix = true; }
387 550
551 bool setHalsOnly() {
552 if (mSerializeFlags) return false;
553 mSerializeFlags |= SerializeFlag::HALS_ONLY;
554 return true;
555 }
556
557 bool setNoHals() {
558 if (mSerializeFlags) return false;
559 mSerializeFlags |= SerializeFlag::NO_HALS;
560 return true;
561 }
562
388 bool addKernel(const std::string& kernelArg) { 563 bool addKernel(const std::string& kernelArg) {
389 auto ind = kernelArg.find(':'); 564 auto ind = kernelArg.find(':');
390 if (ind == std::string::npos) { 565 if (ind == std::string::npos) {
@@ -412,6 +587,7 @@ class AssembleVintf {
412 std::unique_ptr<std::ofstream> mOutFileRef; 587 std::unique_ptr<std::ofstream> mOutFileRef;
413 std::ifstream mCheckFile; 588 std::ifstream mCheckFile;
414 bool mOutputMatrix = false; 589 bool mOutputMatrix = false;
590 SerializeFlags mSerializeFlags = SerializeFlag::EVERYTHING;
415 std::map<Version, std::string> mKernels; 591 std::map<Version, std::string> mKernels;
416}; 592};
417 593
@@ -451,17 +627,25 @@ void help() {
451 " <version> has format: 3.18\n" 627 " <version> has format: 3.18\n"
452 " <android-base.cfg> is the location of android-base.cfg\n" 628 " <android-base.cfg> is the location of android-base.cfg\n"
453 " <android-base-arch.cfg> is the location of an optional\n" 629 " <android-base-arch.cfg> is the location of an optional\n"
454 " arch-specific config fragment, more than one may be specified\n"; 630 " arch-specific config fragment, more than one may be specified\n"
631 " -l, --hals-only\n"
632 " Output has only <hal> entries. Cannot be used with -n.\n"
633 " -n, --no-hals\n"
634 " Output has no <hal> entries (but all other entries).\n"
635 " Cannot be used with -l.\n";
455} 636}
456 637
457int main(int argc, char **argv) { 638int main(int argc, char **argv) {
458 const struct option longopts[] = {{"kernel", required_argument, NULL, 'k'}, {0, 0, 0, 0}}; 639 const struct option longopts[] = {{"kernel", required_argument, NULL, 'k'},
640 {"hals-only", no_argument, NULL, 'l'},
641 {"no-hals", no_argument, NULL, 'n'},
642 {0, 0, 0, 0}};
459 643
460 std::string outFilePath; 644 std::string outFilePath;
461 ::android::vintf::AssembleVintf assembleVintf; 645 ::android::vintf::AssembleVintf assembleVintf;
462 int res; 646 int res;
463 int optind; 647 int optind;
464 while ((res = getopt_long(argc, argv, "hi:o:mc:", longopts, &optind)) >= 0) { 648 while ((res = getopt_long(argc, argv, "hi:o:mc:nl", longopts, &optind)) >= 0) {
465 switch (res) { 649 switch (res) {
466 case 'i': { 650 case 'i': {
467 char* inFilePath = strtok(optarg, ":"); 651 char* inFilePath = strtok(optarg, ":");
@@ -505,6 +689,18 @@ int main(int argc, char **argv) {
505 } 689 }
506 } break; 690 } break;
507 691
692 case 'l': {
693 if (!assembleVintf.setHalsOnly()) {
694 return 1;
695 }
696 } break;
697
698 case 'n': {
699 if (!assembleVintf.setNoHals()) {
700 return 1;
701 }
702 } break;
703
508 case 'h': 704 case 'h':
509 default: { 705 default: {
510 help(); 706 help();
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index bc3fbf4..23cbe53 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -23,6 +23,7 @@
23#include <utils/Errors.h> 23#include <utils/Errors.h>
24 24
25#include "HalGroup.h" 25#include "HalGroup.h"
26#include "Level.h"
26#include "MapValueIterator.h" 27#include "MapValueIterator.h"
27#include "MatrixHal.h" 28#include "MatrixHal.h"
28#include "MatrixKernel.h" 29#include "MatrixKernel.h"
@@ -40,6 +41,7 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat
40 CompatibilityMatrix() : mType(SchemaType::FRAMEWORK) {}; 41 CompatibilityMatrix() : mType(SchemaType::FRAMEWORK) {};
41 42
42 SchemaType type() const; 43 SchemaType type() const;
44 Level level() const;
43 Version getMinimumMetaVersion() const; 45 Version getMinimumMetaVersion() const;
44 46
45 // If the corresponding <xmlfile> with the given version exists, for the first match, 47 // If the corresponding <xmlfile> with the given version exists, for the first match,
@@ -57,6 +59,16 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat
57 bool add(MatrixHal &&hal); 59 bool add(MatrixHal &&hal);
58 bool add(MatrixKernel &&kernel); 60 bool add(MatrixKernel &&kernel);
59 61
62 // Add all HALs as optional HALs from "other". This function moves MatrixHal objects
63 // from "other".
64 // Require other->level() > this->level(), otherwise do nothing.
65 bool addAllHalsAsOptional(CompatibilityMatrix* other, std::string* error);
66 // Return the MatrixHal object with the given name and major version. Since all major
67 // version are guaranteed distinct when add()-ed, there should be at most 1 match.
68 // Return nullptr if none is found.
69 std::pair<MatrixHal*, VersionRange*> getHalWithMajorVersion(const std::string& name,
70 size_t majorVer);
71
60 status_t fetchAllInformation(const std::string &path); 72 status_t fetchAllInformation(const std::string &path);
61 73
62 friend struct HalManifest; 74 friend struct HalManifest;
@@ -68,6 +80,7 @@ struct CompatibilityMatrix : public HalGroup<MatrixHal>, public XmlFileGroup<Mat
68 friend bool operator==(const CompatibilityMatrix &, const CompatibilityMatrix &); 80 friend bool operator==(const CompatibilityMatrix &, const CompatibilityMatrix &);
69 81
70 SchemaType mType; 82 SchemaType mType;
83 Level mLevel = Level::UNSPECIFIED;
71 84
72 // entries only for framework compatibility matrix. 85 // entries only for framework compatibility matrix.
73 struct { 86 struct {
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h
index b553371..46657de 100644
--- a/include/vintf/HalManifest.h
+++ b/include/vintf/HalManifest.h
@@ -24,6 +24,7 @@
24#include <vector> 24#include <vector>
25 25
26#include "HalGroup.h" 26#include "HalGroup.h"
27#include "Level.h"
27#include "ManifestHal.h" 28#include "ManifestHal.h"
28#include "MapValueIterator.h" 29#include "MapValueIterator.h"
29#include "SchemaType.h" 30#include "SchemaType.h"
@@ -93,6 +94,9 @@ struct HalManifest : public HalGroup<ManifestHal>, public XmlFileGroup<ManifestX
93 // Type of the manifest. FRAMEWORK or DEVICE. 94 // Type of the manifest. FRAMEWORK or DEVICE.
94 SchemaType type() const; 95 SchemaType type() const;
95 96
97 // FCM version that it implements.
98 Level level() const;
99
96 // device.mSepolicyVersion. Assume type == device. 100 // device.mSepolicyVersion. Assume type == device.
97 // Abort if type != device. 101 // Abort if type != device.
98 const Version &sepolicyVersion() const; 102 const Version &sepolicyVersion() const;
@@ -132,6 +136,7 @@ struct HalManifest : public HalGroup<ManifestHal>, public XmlFileGroup<ManifestX
132 bool includeOptional = true) const; 136 bool includeOptional = true) const;
133 137
134 SchemaType mType; 138 SchemaType mType;
139 Level mLevel = Level::UNSPECIFIED;
135 // version attribute. Default is 1.0 for manifests created programatically. 140 // version attribute. Default is 1.0 for manifests created programatically.
136 Version mMetaVersion{1, 0}; 141 Version mMetaVersion{1, 0};
137 142
diff --git a/include/vintf/Level.h b/include/vintf/Level.h
new file mode 100644
index 0000000..49dad0b
--- /dev/null
+++ b/include/vintf/Level.h
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_VINTF_LEVEL_H
18#define ANDROID_VINTF_LEVEL_H
19
20#include <stdint.h>
21
22namespace android {
23namespace vintf {
24
25// Manifest and Compatibility Matrix Level, a.k.a FCM Version, is a number assigned to each
26// manifest / matrix.
27// - For manifest, the FCM Version that it implements
28// - For matrix, the single FCM Version that this matrix file details.
29// This is not a strong-typed enum because Level can be any integer value. Listed are some
30// special values.
31enum Level : size_t {
32 // Non-Treble devices.
33 LEGACY = 0,
34 // Actual values starts from 1. Following are some historic values for convenience.
35 O = 1,
36 O_MR1 = 2,
37 // For older manifests and compatibility matrices, "level" is not specified.
38 UNSPECIFIED = SIZE_MAX,
39};
40
41} // namespace vintf
42} // namespace android
43
44#endif // ANDROID_VINTF_LEVEL_H
diff --git a/include/vintf/MatrixHal.h b/include/vintf/MatrixHal.h
index 203aa57..47094fb 100644
--- a/include/vintf/MatrixHal.h
+++ b/include/vintf/MatrixHal.h
@@ -48,6 +48,9 @@ struct MatrixHal {
48 inline bool hasInterface(const std::string& interface_name) const { 48 inline bool hasInterface(const std::string& interface_name) const {
49 return interfaces.find(interface_name) != interfaces.end(); 49 return interfaces.find(interface_name) != interfaces.end();
50 } 50 }
51
52 // Return true if "this" contains all interface/instance instances in "other".
53 bool containsInstances(const MatrixHal& other) const;
51}; 54};
52 55
53} // namespace vintf 56} // namespace vintf
diff --git a/include/vintf/parse_string.h b/include/vintf/parse_string.h
index 77d1830..00844d7 100644
--- a/include/vintf/parse_string.h
+++ b/include/vintf/parse_string.h
@@ -35,6 +35,7 @@ std::ostream &operator<<(std::ostream &os, KernelConfigType il);
35std::ostream &operator<<(std::ostream &os, Tristate tr); 35std::ostream &operator<<(std::ostream &os, Tristate tr);
36std::ostream &operator<<(std::ostream &os, SchemaType ksv); 36std::ostream &operator<<(std::ostream &os, SchemaType ksv);
37std::ostream& operator<<(std::ostream& os, XmlSchemaFormat f); 37std::ostream& operator<<(std::ostream& os, XmlSchemaFormat f);
38std::ostream& operator<<(std::ostream& os, Level l);
38std::ostream &operator<<(std::ostream &os, const ManifestHal &hal); 39std::ostream &operator<<(std::ostream &os, const ManifestHal &hal);
39std::ostream &operator<<(std::ostream &os, const Version &ver); 40std::ostream &operator<<(std::ostream &os, const Version &ver);
40std::ostream &operator<<(std::ostream &os, const VersionRange &vr); 41std::ostream &operator<<(std::ostream &os, const VersionRange &vr);
@@ -60,6 +61,7 @@ bool parse(const std::string &s, KernelConfigKey *key);
60bool parse(const std::string &s, Tristate *tr); 61bool parse(const std::string &s, Tristate *tr);
61bool parse(const std::string &s, SchemaType *ver); 62bool parse(const std::string &s, SchemaType *ver);
62bool parse(const std::string& s, XmlSchemaFormat* ver); 63bool parse(const std::string& s, XmlSchemaFormat* ver);
64bool parse(const std::string& s, Level* l);
63bool parse(const std::string &s, KernelSepolicyVersion *ksv); 65bool parse(const std::string &s, KernelSepolicyVersion *ksv);
64bool parse(const std::string &s, Version *ver); 66bool parse(const std::string &s, Version *ver);
65bool parse(const std::string &s, VersionRange *vr); 67bool parse(const std::string &s, VersionRange *vr);
diff --git a/include/vintf/parse_xml.h b/include/vintf/parse_xml.h
index f1c6a98..61c4f8e 100644
--- a/include/vintf/parse_xml.h
+++ b/include/vintf/parse_xml.h
@@ -23,14 +23,27 @@
23namespace android { 23namespace android {
24namespace vintf { 24namespace vintf {
25 25
26enum SerializeFlag : uint32_t {
27 NO_HALS = 1 << 0,
28 NO_AVB = 1 << 1,
29 NO_SEPOLICY = 1 << 2,
30 NO_VNDK = 1 << 3,
31 NO_KERNEL = 1 << 4,
32 NO_XMLFILES = 1 << 5,
33
34 EVERYTHING = 0,
35 HALS_ONLY = ~NO_HALS,
36};
37using SerializeFlags = uint32_t;
38
26template<typename Object> 39template<typename Object>
27struct XmlConverter { 40struct XmlConverter {
28 XmlConverter() {} 41 XmlConverter() {}
29 virtual ~XmlConverter() {} 42 virtual ~XmlConverter() {}
30 virtual const std::string &lastError() const = 0; 43 virtual const std::string &lastError() const = 0;
31 virtual std::string serialize(const Object &o) const = 0; 44 virtual std::string serialize(const Object& o, SerializeFlags flags = EVERYTHING) const = 0;
32 virtual bool deserialize(Object *o, const std::string &xml) const = 0; 45 virtual bool deserialize(Object *o, const std::string &xml) const = 0;
33 virtual std::string operator()(const Object &o) const = 0; 46 virtual std::string operator()(const Object& o, SerializeFlags flags = EVERYTHING) const = 0;
34 virtual bool operator()(Object *o, const std::string &xml) const = 0; 47 virtual bool operator()(Object *o, const std::string &xml) const = 0;
35}; 48};
36 49
diff --git a/parse_string.cpp b/parse_string.cpp
index a6bb418..7e23f5f 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -113,6 +113,33 @@ std::ostream &operator<<(std::ostream &os, const KernelConfigTypedValue &kctv) {
113 } 113 }
114} 114}
115 115
116bool parse(const std::string& s, Level* l) {
117 if (s.empty()) {
118 *l = Level::UNSPECIFIED;
119 return true;
120 }
121 if (s == "legacy") {
122 *l = Level::LEGACY;
123 return true;
124 }
125 size_t value;
126 if (!ParseUint(s, &value)) {
127 return false;
128 }
129 *l = static_cast<Level>(value);
130 return true;
131}
132
133std::ostream& operator<<(std::ostream& os, Level l) {
134 if (l == Level::UNSPECIFIED) {
135 return os;
136 }
137 if (l == Level::LEGACY) {
138 return os << "legacy";
139 }
140 return os << static_cast<size_t>(l);
141}
142
116// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t, 143// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
117// because strtoull can accept negative values as well. 144// because strtoull can accept negative values as well.
118// Notice that according to man strtoul, strtoull can actually accept 145// Notice that according to man strtoul, strtoull can actually accept
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 1a0626a..3df7e19 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -140,19 +140,23 @@ struct XmlNodeConverter : public XmlConverter<Object> {
140 140
141 // sub-types should implement these. 141 // sub-types should implement these.
142 virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0; 142 virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0;
143 virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags) const {
144 mutateNode(o, n, d);
145 }
143 virtual bool buildObject(Object *o, NodeType *n) const = 0; 146 virtual bool buildObject(Object *o, NodeType *n) const = 0;
144 virtual std::string elementName() const = 0; 147 virtual std::string elementName() const = 0;
145 148
146 // convenience methods for user 149 // convenience methods for user
147 inline const std::string &lastError() const { return mLastError; } 150 inline const std::string &lastError() const { return mLastError; }
148 inline NodeType *serialize(const Object &o, DocType *d) const { 151 inline NodeType* serialize(const Object& o, DocType* d,
152 SerializeFlags flags = EVERYTHING) const {
149 NodeType *root = createNode(this->elementName(), d); 153 NodeType *root = createNode(this->elementName(), d);
150 this->mutateNode(o, root, d); 154 this->mutateNode(o, root, d, flags);
151 return root; 155 return root;
152 } 156 }
153 inline std::string serialize(const Object &o) const { 157 inline std::string serialize(const Object& o, SerializeFlags flags) const {
154 DocType *doc = createDocument(); 158 DocType *doc = createDocument();
155 appendChild(doc, serialize(o, doc)); 159 appendChild(doc, serialize(o, doc, flags));
156 std::string s = printDocument(doc); 160 std::string s = printDocument(doc);
157 deleteDocument(doc); 161 deleteDocument(doc);
158 return s; 162 return s;
@@ -176,8 +180,8 @@ struct XmlNodeConverter : public XmlConverter<Object> {
176 inline NodeType *operator()(const Object &o, DocType *d) const { 180 inline NodeType *operator()(const Object &o, DocType *d) const {
177 return serialize(o, d); 181 return serialize(o, d);
178 } 182 }
179 inline std::string operator()(const Object &o) const { 183 inline std::string operator()(const Object& o, SerializeFlags flags) const {
180 return serialize(o); 184 return serialize(o, flags);
181 } 185 }
182 inline bool operator()(Object *o, NodeType *node) const { 186 inline bool operator()(Object *o, NodeType *node) const {
183 return deserialize(o, node); 187 return deserialize(o, node);
@@ -746,22 +750,38 @@ const ManifestXmlFileConverter manifestXmlFileConverter{};
746struct HalManifestConverter : public XmlNodeConverter<HalManifest> { 750struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
747 std::string elementName() const override { return "manifest"; } 751 std::string elementName() const override { return "manifest"; }
748 void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override { 752 void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override {
753 mutateNode(m, root, d, SerializeFlag::EVERYTHING);
754 }
755 void mutateNode(const HalManifest& m, NodeType* root, DocType* d,
756 SerializeFlags flags) const override {
749 appendAttr(root, "version", m.getMetaVersion()); 757 appendAttr(root, "version", m.getMetaVersion());
750 appendAttr(root, "type", m.mType); 758 appendAttr(root, "type", m.mType);
759 if (m.mLevel != Level::UNSPECIFIED) {
760 this->appendAttr(root, "target-level", m.mLevel);
761 }
751 762
752 appendChildren(root, manifestHalConverter, m.getHals(), d); 763 if (!(flags & SerializeFlag::NO_HALS)) {
764 appendChildren(root, manifestHalConverter, m.getHals(), d);
765 }
753 if (m.mType == SchemaType::DEVICE) { 766 if (m.mType == SchemaType::DEVICE) {
754 appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d)); 767 if (!(flags & SerializeFlag::NO_SEPOLICY)) {
768 appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
769 }
755 } else if (m.mType == SchemaType::FRAMEWORK) { 770 } else if (m.mType == SchemaType::FRAMEWORK) {
756 appendChildren(root, vndkConverter, m.framework.mVndks, d); 771 if (!(flags & SerializeFlag::NO_VNDK)) {
772 appendChildren(root, vndkConverter, m.framework.mVndks, d);
773 }
757 } 774 }
758 775
759 appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d); 776 if (!(flags & SerializeFlag::NO_XMLFILES)) {
777 appendChildren(root, manifestXmlFileConverter, m.getXmlFiles(), d);
778 }
760 } 779 }
761 bool buildObject(HalManifest *object, NodeType *root) const override { 780 bool buildObject(HalManifest *object, NodeType *root) const override {
762 std::vector<ManifestHal> hals; 781 std::vector<ManifestHal> hals;
763 if (!parseAttr(root, "version", &object->mMetaVersion) || 782 if (!parseAttr(root, "version", &object->mMetaVersion) ||
764 !parseAttr(root, "type", &object->mType) || 783 !parseAttr(root, "type", &object->mType) ||
784 !parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel) ||
765 !parseChildren(root, manifestHalConverter, &hals)) { 785 !parseChildren(root, manifestHalConverter, &hals)) {
766 return false; 786 return false;
767 } 787 }
@@ -856,24 +876,44 @@ const MatrixXmlFileConverter matrixXmlFileConverter{};
856struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> { 876struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
857 std::string elementName() const override { return "compatibility-matrix"; } 877 std::string elementName() const override { return "compatibility-matrix"; }
858 void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override { 878 void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override {
879 mutateNode(m, root, d, SerializeFlag::EVERYTHING);
880 }
881 void mutateNode(const CompatibilityMatrix& m, NodeType* root, DocType* d,
882 SerializeFlags flags) const override {
859 appendAttr(root, "version", m.getMinimumMetaVersion()); 883 appendAttr(root, "version", m.getMinimumMetaVersion());
860 appendAttr(root, "type", m.mType); 884 appendAttr(root, "type", m.mType);
861 appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d); 885 if (m.mLevel != Level::UNSPECIFIED) {
886 this->appendAttr(root, "level", m.mLevel);
887 }
888
889 if (!(flags & SerializeFlag::NO_HALS)) {
890 appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d);
891 }
862 if (m.mType == SchemaType::FRAMEWORK) { 892 if (m.mType == SchemaType::FRAMEWORK) {
863 appendChildren(root, matrixKernelConverter, m.framework.mKernels, d); 893 if (!(flags & SerializeFlag::NO_KERNEL)) {
864 appendChild(root, sepolicyConverter(m.framework.mSepolicy, d)); 894 appendChildren(root, matrixKernelConverter, m.framework.mKernels, d);
865 appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d)); 895 }
896 if (!(flags & SerializeFlag::NO_SEPOLICY)) {
897 appendChild(root, sepolicyConverter(m.framework.mSepolicy, d));
898 }
899 if (!(flags & SerializeFlag::NO_AVB)) {
900 appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d));
901 }
866 } else if (m.mType == SchemaType::DEVICE) { 902 } else if (m.mType == SchemaType::DEVICE) {
867 appendChild(root, vndkConverter(m.device.mVndk, d)); 903 if (!(flags & SerializeFlag::NO_VNDK)) {
904 appendChild(root, vndkConverter(m.device.mVndk, d));
905 }
868 } 906 }
869 907
870 appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d); 908 if (!(flags & SerializeFlag::NO_XMLFILES)) {
909 appendChildren(root, matrixXmlFileConverter, m.getXmlFiles(), d);
910 }
871 } 911 }
872 bool buildObject(CompatibilityMatrix *object, NodeType *root) const override { 912 bool buildObject(CompatibilityMatrix *object, NodeType *root) const override {
873 Version version; 913 Version version;
874 std::vector<MatrixHal> hals; 914 std::vector<MatrixHal> hals;
875 if (!parseAttr(root, "version", &version) || 915 if (!parseAttr(root, "version", &version) || !parseAttr(root, "type", &object->mType) ||
876 !parseAttr(root, "type", &object->mType) || 916 !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel) ||
877 !parseChildren(root, matrixHalConverter, &hals)) { 917 !parseChildren(root, matrixHalConverter, &hals)) {
878 return false; 918 return false;
879 } 919 }
diff --git a/test/Android.bp b/test/Android.bp
index ee1cf4f..fe1696c 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -50,11 +50,13 @@ cc_test {
50 "libbase", 50 "libbase",
51 "libcutils", 51 "libcutils",
52 "liblog", 52 "liblog",
53 "libvintftest", 53 "libselinux",
54 "libtinyxml2",
54 ], 55 ],
55 static_libs: [ 56 static_libs: [
56 "libgtest", 57 "libgtest",
57 "libgmock", 58 "libgmock",
59 "libvintftest",
58 ], 60 ],
59 cflags: [ 61 cflags: [
60 "-O0", 62 "-O0",
diff --git a/test/main.cpp b/test/main.cpp
index 8ec02a8..09f2ad0 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -103,6 +103,9 @@ public:
103 return mh.isValid(); 103 return mh.isValid();
104 } 104 }
105 std::vector<MatrixKernel>& getKernels(CompatibilityMatrix& cm) { return cm.framework.mKernels; } 105 std::vector<MatrixKernel>& getKernels(CompatibilityMatrix& cm) { return cm.framework.mKernels; }
106 bool addAllHalsAsOptional(CompatibilityMatrix* cm1, CompatibilityMatrix* cm2, std::string* e) {
107 return cm1->addAllHalsAsOptional(cm2, e);
108 }
106 109
107 std::map<std::string, HalInterface> testHalInterfaces() { 110 std::map<std::string, HalInterface> testHalInterfaces() {
108 HalInterface intf; 111 HalInterface intf;
@@ -2047,6 +2050,188 @@ TEST_P(KernelConfigParserInvalidTest, InvalidLine2) {
2047 2050
2048INSTANTIATE_TEST_CASE_P(KernelConfigParser, KernelConfigParserInvalidTest, ::testing::Bool()); 2051INSTANTIATE_TEST_CASE_P(KernelConfigParser, KernelConfigParserInvalidTest, ::testing::Bool());
2049 2052
2053TEST_F(LibVintfTest, MatrixLevel) {
2054 CompatibilityMatrix cm;
2055 std::string xml;
2056
2057 xml = "<compatibility-matrix version=\"1.0\" type=\"framework\"/>";
2058 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
2059 << gCompatibilityMatrixConverter.lastError();
2060 EXPECT_EQ(Level::UNSPECIFIED, cm.level());
2061
2062 xml = "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"legacy\"/>";
2063 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
2064 << gCompatibilityMatrixConverter.lastError();
2065 EXPECT_EQ(Level::LEGACY, cm.level());
2066
2067 xml = "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\"/>";
2068 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm, xml))
2069 << gCompatibilityMatrixConverter.lastError();
2070 EXPECT_EQ(1u, cm.level());
2071}
2072
2073TEST_F(LibVintfTest, ManifestLevel) {
2074 HalManifest manifest;
2075 std::string xml;
2076
2077 xml = "<manifest version=\"1.0\" type=\"device\"/>";
2078 EXPECT_TRUE(gHalManifestConverter(&manifest, xml)) << gHalManifestConverter.lastError();
2079 EXPECT_EQ(Level::UNSPECIFIED, manifest.level());
2080
2081 xml = "<manifest version=\"1.0\" type=\"device\" target-level=\"legacy\"/>";
2082 EXPECT_TRUE(gHalManifestConverter(&manifest, xml)) << gHalManifestConverter.lastError();
2083 EXPECT_EQ(Level::LEGACY, manifest.level());
2084
2085 xml = "<manifest version=\"1.0\" type=\"device\" target-level=\"1\"/>";
2086 EXPECT_TRUE(gHalManifestConverter(&manifest, xml)) << gHalManifestConverter.lastError();
2087 EXPECT_EQ(1u, manifest.level());
2088}
2089
2090TEST_F(LibVintfTest, AddOptionalHal) {
2091 CompatibilityMatrix cm1;
2092 CompatibilityMatrix cm2;
2093 std::string error;
2094 std::string xml;
2095
2096 xml = "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\"/>";
2097 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm1, xml))
2098 << gCompatibilityMatrixConverter.lastError();
2099
2100 xml =
2101 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"2\">\n"
2102 " <hal format=\"hidl\" optional=\"false\">\n"
2103 " <name>android.hardware.foo</name>\n"
2104 " <version>1.0-1</version>\n"
2105 " <interface>\n"
2106 " <name>IFoo</name>\n"
2107 " <instance>default</instance>\n"
2108 " </interface>\n"
2109 " </hal>\n"
2110 "</compatibility-matrix>\n";
2111 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm2, xml))
2112 << gCompatibilityMatrixConverter.lastError();
2113
2114 EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
2115 xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
2116 EXPECT_EQ(xml,
2117 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
2118 " <hal format=\"hidl\" optional=\"true\">\n"
2119 " <name>android.hardware.foo</name>\n"
2120 " <version>1.0-1</version>\n"
2121 " <interface>\n"
2122 " <name>IFoo</name>\n"
2123 " <instance>default</instance>\n"
2124 " </interface>\n"
2125 " </hal>\n"
2126 "</compatibility-matrix>\n");
2127}
2128
2129TEST_F(LibVintfTest, AddOptionalHalMinorVersion) {
2130 CompatibilityMatrix cm1;
2131 CompatibilityMatrix cm2;
2132 std::string error;
2133 std::string xml;
2134
2135 xml =
2136 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
2137 " <hal format=\"hidl\" optional=\"false\">\n"
2138 " <name>android.hardware.foo</name>\n"
2139 " <version>1.2-3</version>\n"
2140 " <interface>\n"
2141 " <name>IFoo</name>\n"
2142 " <instance>default</instance>\n"
2143 " </interface>\n"
2144 " </hal>\n"
2145 "</compatibility-matrix>\n";
2146 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm1, xml))
2147 << gCompatibilityMatrixConverter.lastError();
2148
2149 xml =
2150 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"2\">\n"
2151 " <hal format=\"hidl\" optional=\"false\">\n"
2152 " <name>android.hardware.foo</name>\n"
2153 " <version>1.0-4</version>\n"
2154 " <interface>\n"
2155 " <name>IFoo</name>\n"
2156 " <instance>default</instance>\n"
2157 " </interface>\n"
2158 " </hal>\n"
2159 "</compatibility-matrix>\n";
2160 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm2, xml))
2161 << gCompatibilityMatrixConverter.lastError();
2162
2163 EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
2164 xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
2165 EXPECT_EQ(xml,
2166 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
2167 " <hal format=\"hidl\" optional=\"false\">\n"
2168 " <name>android.hardware.foo</name>\n"
2169 " <version>1.2-4</version>\n"
2170 " <interface>\n"
2171 " <name>IFoo</name>\n"
2172 " <instance>default</instance>\n"
2173 " </interface>\n"
2174 " </hal>\n"
2175 "</compatibility-matrix>\n");
2176}
2177
2178TEST_F(LibVintfTest, AddOptionalHalMajorVersion) {
2179 CompatibilityMatrix cm1;
2180 CompatibilityMatrix cm2;
2181 std::string error;
2182 std::string xml;
2183
2184 xml =
2185 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
2186 " <hal format=\"hidl\" optional=\"false\">\n"
2187 " <name>android.hardware.foo</name>\n"
2188 " <version>1.2-3</version>\n"
2189 " <interface>\n"
2190 " <name>IFoo</name>\n"
2191 " <instance>default</instance>\n"
2192 " </interface>\n"
2193 " </hal>\n"
2194 "</compatibility-matrix>\n";
2195 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm1, xml))
2196 << gCompatibilityMatrixConverter.lastError();
2197
2198 xml =
2199 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"2\">\n"
2200 " <hal format=\"hidl\" optional=\"false\">\n"
2201 " <name>android.hardware.foo</name>\n"
2202 " <version>2.0-4</version>\n"
2203 " <interface>\n"
2204 " <name>IFoo</name>\n"
2205 " <instance>default</instance>\n"
2206 " </interface>\n"
2207 " </hal>\n"
2208 "</compatibility-matrix>\n";
2209 EXPECT_TRUE(gCompatibilityMatrixConverter(&cm2, xml))
2210 << gCompatibilityMatrixConverter.lastError();
2211
2212 EXPECT_TRUE(addAllHalsAsOptional(&cm1, &cm2, &error)) << error;
2213 xml = gCompatibilityMatrixConverter(cm1, SerializeFlag::HALS_ONLY);
2214 EXPECT_EQ(xml,
2215 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\">\n"
2216 " <hal format=\"hidl\" optional=\"false\">\n"
2217 " <name>android.hardware.foo</name>\n"
2218 " <version>1.2-3</version>\n"
2219 " <interface>\n"
2220 " <name>IFoo</name>\n"
2221 " <instance>default</instance>\n"
2222 " </interface>\n"
2223 " </hal>\n"
2224 " <hal format=\"hidl\" optional=\"true\">\n"
2225 " <name>android.hardware.foo</name>\n"
2226 " <version>2.0-4</version>\n"
2227 " <interface>\n"
2228 " <name>IFoo</name>\n"
2229 " <instance>default</instance>\n"
2230 " </interface>\n"
2231 " </hal>\n"
2232 "</compatibility-matrix>\n");
2233}
2234
2050} // namespace vintf 2235} // namespace vintf
2051} // namespace android 2236} // namespace android
2052 2237