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