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 #define LOG_TAG "libvintf"
18 #include <android-base/logging.h>
19
20 #include "HalManifest.h"
21
22 #include <dirent.h>
23
24 #include <mutex>
25 #include <set>
26
27 #include <android-base/strings.h>
28
29 #include "CompatibilityMatrix.h"
30 #include "constants-private.h"
31 #include "constants.h"
32 #include "parse_string.h"
33 #include "parse_xml.h"
34 #include "utils.h"
35
36 namespace android {
37 namespace vintf {
38
39 using details::Instances;
40 using details::InstancesOfVersion;
41 using details::mergeField;
42
43 // Check <version> tag for all <hal> with the same name.
shouldAdd(const ManifestHal & hal,std::string * error) const44 bool HalManifest::shouldAdd(const ManifestHal& hal, std::string* error) const {
45 if (!hal.isValid(error)) {
46 if (error) {
47 error->insert(0, "HAL '" + hal.name + "' is not valid: ");
48 if (!hal.fileName().empty()) {
49 error->insert(0, "For file " + hal.fileName() + ": ");
50 }
51 }
52 return false;
53 }
54 if (hal.isOverride()) {
55 return true;
56 }
57 return addingConflictingMajorVersion(hal, error);
58 }
59
addingConflictingMajorVersion(const ManifestHal & hal,std::string * error) const60 bool HalManifest::addingConflictingMajorVersion(const ManifestHal& hal, std::string* error) const {
61 // Skip checking for AIDL HALs because they all contain kFakeAidlMajorVersion.
62 if (hal.format == HalFormat::AIDL) {
63 return true;
64 }
65
66 auto existingHals = mHals.equal_range(hal.name);
67 std::map<size_t, std::tuple<const ManifestHal*, Version>> existing;
68 for (auto it = existingHals.first; it != existingHals.second; ++it) {
69 const ManifestHal& existingHal = it->second;
70 for (const auto& v : existingHal.versions) {
71 // Assume integrity on existingHals, so no check on emplace().second
72 existing.emplace(v.majorVer, std::make_tuple(&existingHal, v));
73 }
74 }
75 bool success = true;
76 for (const auto& v : hal.versions) {
77 auto&& [existingIt, inserted] = existing.emplace(v.majorVer, std::make_tuple(&hal, v));
78 if (inserted) {
79 continue;
80 }
81 success = false;
82 if (error) {
83 auto&& [existingHal, existingVersion] = existingIt->second;
84 *error = "Conflicting major version: " + to_string(existingVersion);
85 if (!existingHal->fileName().empty()) {
86 *error += " (from " + existingHal->fileName() + ")";
87 }
88 *error += " vs. " + to_string(v);
89 if (!hal.fileName().empty()) {
90 *error += " (from " + hal.fileName() + ")";
91 }
92 *error +=
93 ". Check whether or not multiple modules providing the same HAL are installed.";
94 }
95 }
96 return success;
97 }
98
99 // Remove elements from "list" if p(element) returns true.
100 template <typename List, typename Predicate>
removeIf(List & list,Predicate predicate)101 static void removeIf(List& list, Predicate predicate) {
102 for (auto it = list.begin(); it != list.end();) {
103 if (predicate(*it)) {
104 it = list.erase(it);
105 } else {
106 ++it;
107 }
108 }
109 }
110
removeHals(const std::string & name,size_t majorVer)111 void HalManifest::removeHals(const std::string& name, size_t majorVer) {
112 removeIf(mHals, [&name, majorVer](auto& existingHalPair) {
113 auto& existingHal = existingHalPair.second;
114 if (existingHal.name != name) {
115 return false;
116 }
117 auto& existingVersions = existingHal.versions;
118 removeIf(existingVersions, [majorVer](const auto& existingVersion) {
119 return existingVersion.majorVer == majorVer;
120 });
121 return existingVersions.empty();
122 });
123 }
124
add(ManifestHal && halToAdd,std::string * error)125 bool HalManifest::add(ManifestHal&& halToAdd, std::string* error) {
126 if (halToAdd.isOverride()) {
127 if (halToAdd.isDisabledHal()) {
128 // Special syntax when there are no instances at all. Remove all existing HALs
129 // with the given name.
130 mHals.erase(halToAdd.name);
131 }
132 // If there are <version> tags, remove all existing major versions that causes a conflict.
133 for (const Version& versionToAdd : halToAdd.versions) {
134 removeHals(halToAdd.name, versionToAdd.majorVer);
135 }
136 }
137
138 if (!shouldAdd(halToAdd, error)) {
139 return false;
140 }
141
142 CHECK(addInternal(std::move(halToAdd)) != nullptr);
143 return true;
144 }
145
addAllHals(HalManifest * other,std::string * error)146 bool HalManifest::addAllHals(HalManifest* other, std::string* error) {
147 for (auto& pair : other->mHals) {
148 if (!add(std::move(pair.second), error)) {
149 if (error) {
150 error->insert(0, "HAL \"" + pair.first + "\" has a conflict: ");
151 }
152 return false;
153 }
154 }
155 other->mHals.clear();
156 return true;
157 }
158
shouldAddXmlFile(const ManifestXmlFile & xmlFile) const159 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const {
160 auto existingXmlFiles = getXmlFiles(xmlFile.name());
161 for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) {
162 if (xmlFile.version() == it->second.version()) {
163 return false;
164 }
165 }
166 return true;
167 }
168
getHalNames() const169 std::set<std::string> HalManifest::getHalNames() const {
170 std::set<std::string> names{};
171 for (const auto &hal : mHals) {
172 names.insert(hal.first);
173 }
174 return names;
175 }
176
getHalNamesAndVersions() const177 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
178 std::set<std::string> names{};
179 forEachInstance([&names](const ManifestInstance& e) {
180 switch (e.format()) {
181 case HalFormat::HIDL:
182 [[fallthrough]];
183 case HalFormat::NATIVE:
184 names.insert(toFQNameString(e.package(), e.version()));
185 break;
186 case HalFormat::AIDL:
187 names.insert(e.package());
188 break;
189 }
190 return true;
191 });
192 return names;
193 }
194
getHidlTransport(const std::string & package,const Version & v,const std::string & interfaceName,const std::string & instanceName) const195 Transport HalManifest::getHidlTransport(const std::string& package, const Version& v,
196 const std::string& interfaceName,
197 const std::string& instanceName) const {
198 Transport transport{Transport::EMPTY};
199 forEachInstanceOfInterface(HalFormat::HIDL, package, v, interfaceName, [&](const auto& e) {
200 if (e.instance() == instanceName) {
201 transport = e.transport();
202 }
203 return transport == Transport::EMPTY; // if not found, continue
204 });
205 if (transport == Transport::EMPTY) {
206 LOG(DEBUG) << "HalManifest::getHidlTransport(" << mType << "): Cannot find "
207 << toFQNameString(package, v, interfaceName, instanceName);
208 }
209 return transport;
210 }
211
forEachInstanceOfVersion(HalFormat format,const std::string & package,const Version & expectVersion,const std::function<bool (const ManifestInstance &)> & func) const212 bool HalManifest::forEachInstanceOfVersion(
213 HalFormat format, const std::string& package, const Version& expectVersion,
214 const std::function<bool(const ManifestInstance&)>& func) const {
215 for (const ManifestHal* hal : getHals(package)) {
216 bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
217 if (manifestInstance.format() == format &&
218 manifestInstance.version().minorAtLeast(expectVersion)) {
219 return func(manifestInstance);
220 }
221 return true;
222 });
223 if (!cont) return false;
224 }
225 return true;
226 }
227
228 // indent = 2, {"foo"} => "foo"
229 // indent = 2, {"foo", "bar"} => "\n foo\n bar";
230 template <typename Container>
multilineIndent(std::ostream & os,size_t indent,const Container & lines)231 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) {
232 if (lines.size() == 1) {
233 os << *lines.begin();
234 return;
235 }
236 for (const auto& line : lines) {
237 os << "\n";
238 for (size_t i = 0; i < indent; ++i) os << " ";
239 os << line;
240 }
241 }
242
243 // For each hal in mat, there must be a hal in manifest that supports this.
checkIncompatibleHals(const CompatibilityMatrix & mat) const244 std::vector<std::string> HalManifest::checkIncompatibleHals(const CompatibilityMatrix& mat) const {
245 std::vector<std::string> ret;
246 for (const MatrixHal &matrixHal : mat.getHals()) {
247 if (matrixHal.optional) {
248 continue;
249 }
250
251 std::set<FqInstance> manifestInstances;
252 std::set<std::string> manifestInstanceDesc;
253 std::set<Version> versions;
254 for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
255 manifestHal->forEachInstance([&](const auto& manifestInstance) {
256 manifestInstances.insert(manifestInstance.getFqInstance());
257 manifestInstanceDesc.insert(manifestInstance.descriptionWithoutPackage());
258 return true;
259 });
260 manifestHal->appendAllVersions(&versions);
261 }
262
263 if (!matrixHal.isCompatible(manifestInstances, versions)) {
264 std::ostringstream oss;
265 oss << matrixHal.name << ":\n required: ";
266 multilineIndent(oss, 8, android::vintf::expandInstances(matrixHal));
267 oss << "\n provided: ";
268 if (manifestInstances.empty()) {
269 multilineIndent(oss, 8, versions);
270 } else {
271 multilineIndent(oss, 8, manifestInstanceDesc);
272 }
273
274 ret.insert(ret.end(), oss.str());
275 }
276 }
277 return ret;
278 }
279
checkUnusedHals(const CompatibilityMatrix & mat,const std::vector<HidlInterfaceMetadata> & hidlMetadata) const280 std::set<std::string> HalManifest::checkUnusedHals(
281 const CompatibilityMatrix& mat, const std::vector<HidlInterfaceMetadata>& hidlMetadata) const {
282 std::multimap<std::string, std::string> childrenMap;
283 for (const auto& child : hidlMetadata) {
284 for (const auto& parent : child.inherited) {
285 childrenMap.emplace(parent, child.name);
286 }
287 }
288
289 std::set<std::string> ret;
290
291 forEachInstance([&ret, &mat, &childrenMap](const auto& manifestInstance) {
292 if (mat.matchInstance(manifestInstance.format(), manifestInstance.package(),
293 manifestInstance.version(), manifestInstance.interface(),
294 manifestInstance.instance())) {
295 // manifestInstance exactly matches an instance in |mat|.
296 return true;
297 }
298 // For HIDL instances, If foo@2.0 inherits from foo@1.0, manifest may contain both, but
299 // matrix may contain only 2.0 if 1.0 is considered deprecated. Hence, if manifestInstance
300 // is 1.0, check all its children in the matrix too.
301 // If there is at least one match, do not consider it unused.
302 if (manifestInstance.format() == HalFormat::HIDL) {
303 auto range =
304 childrenMap.equal_range(manifestInstance.getFqInstance().getFqName().string());
305 for (auto it = range.first; it != range.second; ++it) {
306 FQName fqName;
307 CHECK(fqName.setTo(it->second));
308 if (mat.matchInstance(manifestInstance.format(), fqName.package(),
309 fqName.getVersion(), fqName.name(),
310 manifestInstance.instance())) {
311 return true;
312 }
313 }
314 }
315
316 // If no match is found, consider it unused.
317 ret.insert(manifestInstance.description());
318 return true;
319 });
320
321 return ret;
322 }
323
checkVendorNdkCompatibility(const VendorNdk & matVendorNdk,const std::vector<VendorNdk> & manifestVendorNdk,std::string * error)324 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
325 const std::vector<VendorNdk>& manifestVendorNdk,
326 std::string* error) {
327 // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
328 // tag. Ignore the check for these devices.
329 if (matVendorNdk.version().empty()) {
330 return true;
331 }
332 for (const auto& vndk : manifestVendorNdk) {
333 if (vndk.version() != matVendorNdk.version()) {
334 continue;
335 }
336 // version matches, check libraries
337 std::vector<std::string> diff;
338 std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
339 vndk.libraries().begin(), vndk.libraries().end(),
340 std::inserter(diff, diff.begin()));
341 if (!diff.empty()) {
342 if (error != nullptr) {
343 *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
344 ". These libs are not in framework manifest:";
345 for (const auto& name : diff) {
346 *error += " " + name;
347 }
348 }
349 return false;
350 }
351 return true;
352 }
353
354 // no match is found.
355 if (error != nullptr) {
356 *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
357 "Supported versions in framework manifest are: [";
358 for (const auto& vndk : manifestVendorNdk) {
359 *error += " " + vndk.version();
360 }
361 *error += "]";
362 }
363 return false;
364 }
365
checkSystemSdkCompatibility(const SystemSdk & matSystemSdk,const SystemSdk & manifestSystemSdk,std::string * error)366 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk,
367 const SystemSdk& manifestSystemSdk, std::string* error) {
368 SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk);
369 if (!notSupported.empty()) {
370 if (error) {
371 *error =
372 "The following System SDK versions are required by device "
373 "compatibility matrix but not supported by the framework manifest: [" +
374 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" +
375 base::Join(manifestSystemSdk.versions(), ", ") + "].";
376 }
377 return false;
378 }
379 return true;
380 }
381
checkCompatibility(const CompatibilityMatrix & mat,std::string * error,CheckFlags::Type flags) const382 bool HalManifest::checkCompatibility(const CompatibilityMatrix& mat, std::string* error,
383 CheckFlags::Type flags) const {
384 if (mType == mat.mType) {
385 if (error != nullptr) {
386 *error = "Wrong type; checking " + to_string(mType) + " manifest against "
387 + to_string(mat.mType) + " compatibility matrix";
388 }
389 return false;
390 }
391 auto incompatibleHals = checkIncompatibleHals(mat);
392 if (!incompatibleHals.empty()) {
393 if (error != nullptr) {
394 *error = "HALs incompatible.";
395 if (mat.level() != Level::UNSPECIFIED)
396 *error += " Matrix level = " + to_string(mat.level()) + ".";
397 if (level() != Level::UNSPECIFIED)
398 *error += " Manifest level = " + to_string(level()) + ".";
399 *error += " The following requirements are not met:\n";
400 for (const auto& e : incompatibleHals) {
401 *error += e + "\n";
402 }
403 }
404 return false;
405 }
406 if (mType == SchemaType::FRAMEWORK) {
407 if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
408 return false;
409 }
410
411 if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) {
412 return false;
413 }
414 } else if (mType == SchemaType::DEVICE) {
415 bool sepolicyMatch = false;
416 for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
417 if (range.supportedBy(device.mSepolicyVersion)) {
418 sepolicyMatch = true;
419 break;
420 }
421 }
422 if (!sepolicyMatch) {
423 if (error != nullptr) {
424 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
425 + " doesn't satisify the requirements.";
426 }
427 return false;
428 }
429
430 // Not using inferredKernelLevel() to preserve the legacy behavior if <kernel> does not have
431 // level attribute.
432 // Note that shouldCheckKernelCompatibility() only returns true on host, because the
433 // on-device HalManifest does not have kernel version set. On the device, kernel information
434 // is retrieved from RuntimeInfo.
435 Level kernelTagLevel = kernel()->level();
436 if (flags.isKernelEnabled() && shouldCheckKernelCompatibility() &&
437 kernel()
438 ->getMatchedKernelRequirements(mat.framework.mKernels, kernelTagLevel, error)
439 .empty()) {
440 return false;
441 }
442 }
443
444 return true;
445 }
446
shouldCheckKernelCompatibility() const447 bool HalManifest::shouldCheckKernelCompatibility() const {
448 return kernel().has_value() && kernel()->version() != KernelVersion{};
449 }
450
generateCompatibleMatrix(bool optional) const451 CompatibilityMatrix HalManifest::generateCompatibleMatrix(bool optional) const {
452 CompatibilityMatrix matrix;
453
454 std::set<std::tuple<HalFormat, std::string, Version, std::string, std::string>> instances;
455
456 forEachInstance([&matrix, &instances, optional](const ManifestInstance& e) {
457 auto&& [it, added] =
458 instances.emplace(e.format(), e.package(), e.version(), e.interface(), e.instance());
459 if (!added) {
460 return true;
461 }
462
463 matrix.add(MatrixHal{
464 .format = e.format(),
465 .name = e.package(),
466 .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}},
467 .optional = optional,
468 .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}});
469 return true;
470 });
471 if (mType == SchemaType::FRAMEWORK) {
472 matrix.mType = SchemaType::DEVICE;
473 // VNDK does not need to be added for compatibility
474 } else if (mType == SchemaType::DEVICE) {
475 matrix.mType = SchemaType::FRAMEWORK;
476 matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
477 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
478 }
479
480 return matrix;
481 }
482
fetchAllInformation(const FileSystem * fileSystem,const std::string & path,std::string * error)483 status_t HalManifest::fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
484 std::string* error) {
485 return details::fetchAllInformation(fileSystem, path, this, error);
486 }
487
type() const488 SchemaType HalManifest::type() const {
489 return mType;
490 }
491
setType(SchemaType type)492 void HalManifest::setType(SchemaType type) {
493 mType = type;
494 }
495
level() const496 Level HalManifest::level() const {
497 return mLevel;
498 }
499
getMetaVersion() const500 Version HalManifest::getMetaVersion() const {
501 return kMetaVersion;
502 }
503
sepolicyVersion() const504 const Version &HalManifest::sepolicyVersion() const {
505 CHECK(mType == SchemaType::DEVICE);
506 return device.mSepolicyVersion;
507 }
508
vendorNdks() const509 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
510 CHECK(mType == SchemaType::FRAMEWORK);
511 return framework.mVendorNdks;
512 }
513
getXmlFilePath(const std::string & xmlFileName,const Version & version) const514 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
515 const Version& version) const {
516 using std::literals::string_literals::operator""s;
517 auto range = getXmlFiles(xmlFileName);
518 for (auto it = range.first; it != range.second; ++it) {
519 const ManifestXmlFile& manifestXmlFile = it->second;
520 if (manifestXmlFile.version() == version) {
521 if (!manifestXmlFile.overriddenPath().empty()) {
522 return manifestXmlFile.overriddenPath();
523 }
524 return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
525 xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
526 std::to_string(version.minorVer) + ".xml";
527 }
528 }
529 return "";
530 }
531
operator ==(const HalManifest & lft,const HalManifest & rgt)532 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
533 // ignore fileName().
534 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
535 lft.mXmlFiles == rgt.mXmlFiles &&
536 (lft.mType != SchemaType::DEVICE ||
537 (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion &&
538 lft.device.mKernel == rgt.device.mKernel)) &&
539 (lft.mType != SchemaType::FRAMEWORK ||
540 (
541 #pragma clang diagnostic push
542 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
543 lft.framework.mVndks == rgt.framework.mVndks &&
544 #pragma clang diagnostic pop
545 lft.framework.mVendorNdks == rgt.framework.mVendorNdks &&
546 lft.framework.mSystemSdk == rgt.framework.mSystemSdk));
547 }
548
549 // Alternative to forEachInstance if you just need a set of instance names instead.
getInstances(HalFormat format,const std::string & package,const Version & version,const std::string & interfaceName) const550 std::set<std::string> HalManifest::getInstances(HalFormat format, const std::string& package,
551 const Version& version,
552 const std::string& interfaceName) const {
553 std::set<std::string> ret;
554 (void)forEachInstanceOfInterface(format, package, version, interfaceName,
555 [&ret](const auto& e) {
556 ret.insert(e.instance());
557 return true;
558 });
559 return ret;
560 }
561
562 // Return whether instance is in getInstances(...).
hasInstance(HalFormat format,const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const563 bool HalManifest::hasInstance(HalFormat format, const std::string& package, const Version& version,
564 const std::string& interfaceName, const std::string& instance) const {
565 bool found = false;
566 (void)forEachInstanceOfInterface(format, package, version, interfaceName,
567 [&found, &instance](const auto& e) {
568 found |= (instance == e.instance());
569 return !found; // if not found, continue
570 });
571 return found;
572 }
getHidlInstances(const std::string & package,const Version & version,const std::string & interfaceName) const573 std::set<std::string> HalManifest::getHidlInstances(const std::string& package,
574 const Version& version,
575 const std::string& interfaceName) const {
576 return getInstances(HalFormat::HIDL, package, version, interfaceName);
577 }
578
getAidlInstances(const std::string & package,const std::string & interfaceName) const579 std::set<std::string> HalManifest::getAidlInstances(const std::string& package,
580 const std::string& interfaceName) const {
581 return getAidlInstances(package, 0, interfaceName);
582 }
583
getAidlInstances(const std::string & package,size_t version,const std::string & interfaceName) const584 std::set<std::string> HalManifest::getAidlInstances(const std::string& package, size_t version,
585 const std::string& interfaceName) const {
586 return getInstances(HalFormat::AIDL, package, {details::kFakeAidlMajorVersion, version},
587 interfaceName);
588 }
589
hasHidlInstance(const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const590 bool HalManifest::hasHidlInstance(const std::string& package, const Version& version,
591 const std::string& interfaceName,
592 const std::string& instance) const {
593 return hasInstance(HalFormat::HIDL, package, version, interfaceName, instance);
594 }
595
hasAidlInstance(const std::string & package,const std::string & interface,const std::string & instance) const596 bool HalManifest::hasAidlInstance(const std::string& package, const std::string& interface,
597 const std::string& instance) const {
598 return hasAidlInstance(package, 0, interface, instance);
599 }
600
hasAidlInstance(const std::string & package,size_t version,const std::string & interface,const std::string & instance) const601 bool HalManifest::hasAidlInstance(const std::string& package, size_t version,
602 const std::string& interface, const std::string& instance) const {
603 return hasInstance(HalFormat::AIDL, package, {details::kFakeAidlMajorVersion, version},
604 interface, instance);
605 }
606
insertInstance(const FqInstance & fqInstance,Transport transport,Arch arch,HalFormat format,std::string * error)607 bool HalManifest::insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch,
608 HalFormat format, std::string* error) {
609 for (ManifestHal& hal : getHals()) {
610 if (hal.name == fqInstance.getPackage() && hal.format == format &&
611 hal.transport() == transport && hal.arch() == arch) {
612 return hal.insertInstance(fqInstance, error);
613 }
614 }
615
616 ManifestHal hal;
617 hal.name = fqInstance.getPackage();
618 hal.format = format;
619 hal.transportArch = TransportArch(transport, arch);
620 if (!hal.insertInstance(fqInstance, error)) return false;
621 return add(std::move(hal));
622 }
623
empty() const624 bool HalManifest::empty() const {
625 HalManifest emptyManifest;
626 emptyManifest.setType(type());
627 return (*this) == emptyManifest;
628 }
629
kernel() const630 const std::optional<KernelInfo>& HalManifest::kernel() const {
631 return device.mKernel;
632 }
633
mergeKernel(std::optional<KernelInfo> * other,std::string * error)634 bool HalManifest::mergeKernel(std::optional<KernelInfo>* other, std::string* error) {
635 if (!other->has_value()) {
636 return true;
637 }
638
639 if (device.mKernel.has_value()) {
640 if (!device.mKernel->merge(&**other, error)) {
641 return false;
642 }
643 } else {
644 device.mKernel = std::move(*other);
645 }
646
647 *other = std::nullopt;
648 return true;
649 }
650
addAll(HalManifest * other,std::string * error)651 bool HalManifest::addAll(HalManifest* other, std::string* error) {
652 if (type() != other->type()) {
653 if (error) {
654 *error = "Cannot add a " + to_string(other->type()) + " manifest to a " +
655 to_string(type()) + " manifest";
656 }
657 return false;
658 }
659
660 if (!addAllHals(other, error)) {
661 return false;
662 }
663
664 if (!addAllXmlFiles(other, error)) {
665 return false;
666 }
667
668 if (!mergeField(&mLevel, &other->mLevel, Level::UNSPECIFIED)) {
669 if (error) {
670 *error = "Conflicting target-level: " + to_string(level()) + " vs. " +
671 to_string(other->level());
672 }
673 return false;
674 }
675
676 if (type() == SchemaType::DEVICE) {
677 if (!mergeField(&device.mSepolicyVersion, &other->device.mSepolicyVersion)) {
678 if (error) {
679 *error = "Conflicting sepolicy version: " + to_string(sepolicyVersion()) + " vs. " +
680 to_string(other->sepolicyVersion());
681 }
682 return false;
683 }
684
685 if (!mergeKernel(&other->device.mKernel, error)) {
686 return false;
687 }
688 } else if (type() == SchemaType::FRAMEWORK) {
689 #pragma clang diagnostic push
690 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
691 framework.mVndks.insert(framework.mVndks.end(), other->framework.mVndks.begin(),
692 other->framework.mVndks.end());
693 other->framework.mVndks.clear();
694 #pragma clang diagnostic pop
695
696 framework.mVendorNdks.insert(framework.mVendorNdks.end(),
697 other->framework.mVendorNdks.begin(),
698 other->framework.mVendorNdks.end());
699 other->framework.mVendorNdks.clear();
700
701 framework.mSystemSdk.addAll(&other->framework.mSystemSdk);
702 } else {
703 LOG(FATAL) << "unknown SchemaType: "
704 << static_cast<std::underlying_type_t<SchemaType>>(type());
705 }
706
707 if (!other->empty()) {
708 if (error) {
709 *error =
710 "Cannot add another manifest because it contains extraneous entries that "
711 "are not recognized.";
712 }
713 return false;
714 }
715
716 return true;
717 }
718
inferredKernelLevel() const719 Level HalManifest::inferredKernelLevel() const {
720 if (kernel().has_value()) {
721 if (kernel()->level() != Level::UNSPECIFIED) {
722 return kernel()->level();
723 }
724 }
725 // As a special case, for devices launching with R and above, also infer from <manifest>.level.
726 // Devices launching before R may leave kernel level unspecified to use legacy kernel
727 // matching behavior; see KernelInfo::getMatchedKernelRequirements.
728 if (level() >= Level::R) {
729 return level();
730 }
731 return Level::UNSPECIFIED;
732 }
733
734 } // namespace vintf
735 } // namespace android
736