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