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