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.
44 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 
60 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>
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 
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 
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 
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 
159 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 
169 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 
177 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 
195 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 
212 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>
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.
244 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 
280 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 
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 
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 
382 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 
447 bool HalManifest::shouldCheckKernelCompatibility() const {
448     return kernel().has_value() && kernel()->version() != KernelVersion{};
449 }
450 
451 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 
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 
488 SchemaType HalManifest::type() const {
489     return mType;
490 }
491 
492 void HalManifest::setType(SchemaType type) {
493     mType = type;
494 }
495 
496 Level HalManifest::level() const {
497     return mLevel;
498 }
499 
500 Version HalManifest::getMetaVersion() const {
501     return kMetaVersion;
502 }
503 
504 const Version &HalManifest::sepolicyVersion() const {
505     CHECK(mType == SchemaType::DEVICE);
506     return device.mSepolicyVersion;
507 }
508 
509 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
510     CHECK(mType == SchemaType::FRAMEWORK);
511     return framework.mVendorNdks;
512 }
513 
514 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 
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.
550 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(...).
563 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 }
573 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 
579 std::set<std::string> HalManifest::getAidlInstances(const std::string& package,
580                                                     const std::string& interfaceName) const {
581     return getAidlInstances(package, 0, interfaceName);
582 }
583 
584 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 
590 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 
596 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 
601 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 
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 
624 bool HalManifest::empty() const {
625     HalManifest emptyManifest;
626     emptyManifest.setType(type());
627     return (*this) == emptyManifest;
628 }
629 
630 const std::optional<KernelInfo>& HalManifest::kernel() const {
631     return device.mKernel;
632 }
633 
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 
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 
719 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