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 if (!addingConflictingMajorVersion(hal, error)) {
58 return false;
59 }
60 return addingConflictingFqInstance(hal, error);
61 }
62
addingConflictingMajorVersion(const ManifestHal & hal,std::string * error) const63 bool HalManifest::addingConflictingMajorVersion(const ManifestHal& hal, std::string* error) const {
64 // Skip checking for AIDL HALs because they all contain kFakeAidlMajorVersion.
65 if (hal.format == HalFormat::AIDL) {
66 return true;
67 }
68
69 auto existingHals = mHals.equal_range(hal.name);
70 std::map<size_t, std::tuple<const ManifestHal*, Version>> existing;
71 for (auto it = existingHals.first; it != existingHals.second; ++it) {
72 const ManifestHal& existingHal = it->second;
73 for (const auto& v : existingHal.versions) {
74 // Assume integrity on existingHals, so no check on emplace().second
75 existing.emplace(v.majorVer, std::make_tuple(&existingHal, v));
76 }
77 }
78 bool success = true;
79 for (const auto& v : hal.versions) {
80 auto&& [existingIt, inserted] = existing.emplace(v.majorVer, std::make_tuple(&hal, v));
81 if (inserted) {
82 continue;
83 }
84 success = false;
85 if (error) {
86 auto&& [existingHal, existingVersion] = existingIt->second;
87 *error = "Conflicting major version: " + to_string(existingVersion);
88 if (!existingHal->fileName().empty()) {
89 *error += " (from " + existingHal->fileName() + ")";
90 }
91 *error += " vs. " + to_string(v);
92 if (!hal.fileName().empty()) {
93 *error += " (from " + hal.fileName() + ")";
94 }
95 *error +=
96 ". Check whether or not multiple modules providing the same HAL are installed.";
97 }
98 }
99
100 return success;
101 }
102
addingConflictingFqInstance(const ManifestHal & halToAdd,std::string * error) const103 bool HalManifest::addingConflictingFqInstance(const ManifestHal& halToAdd,
104 std::string* error) const {
105 if (mSourceMetaVersion < kMetaVersionNoHalInterfaceInstance) {
106 return true;
107 }
108
109 auto existingHals = mHals.equal_range(halToAdd.name);
110
111 // Key: FqInstance with minor version 0
112 // Value: original HAL and FqInstance
113 std::map<FqInstance, std::tuple<const ManifestHal*, ManifestInstance>> existing;
114 for (auto it = existingHals.first; it != existingHals.second; ++it) {
115 const ManifestHal& existingHal = it->second;
116 bool success =
117 existingHal.forEachInstance([&existingHal, &existing](const auto& manifestInstance) {
118 auto versionZero = manifestInstance.version().withMinor(0);
119 auto key = manifestInstance.withVersion(versionZero).getFqInstance();
120 // Assume integrity on existingHals, so no check on emplace().second
121 existing.emplace(key, std::make_tuple(&existingHal, manifestInstance));
122 return true; // continue
123 });
124 if (!success) {
125 return false;
126 }
127 }
128 return halToAdd.forEachInstance(
129 [&halToAdd, &existing, error](const auto& manifestInstanceToAdd) {
130 auto versionZero = manifestInstanceToAdd.version().withMinor(0);
131 auto key = manifestInstanceToAdd.withVersion(versionZero).getFqInstance();
132
133 auto&& [existingIt, inserted] =
134 existing.emplace(key, std::make_tuple(&halToAdd, manifestInstanceToAdd));
135 if (inserted) {
136 return true; // continue
137 }
138
139 if (error) {
140 auto&& [existingHal, existingManifestInstance] = existingIt->second;
141 *error = "Conflicting FqInstance: ";
142 *error += existingManifestInstance.descriptionWithoutPackage();
143 if (!existingHal->fileName().empty()) {
144 *error += " (from " + existingHal->fileName() + ")";
145 }
146 *error += " vs. " + manifestInstanceToAdd.descriptionWithoutPackage();
147 if (!halToAdd.fileName().empty()) {
148 *error += " (from " + halToAdd.fileName() + ")";
149 }
150 *error +=
151 ". Check whether or not multiple modules providing the same HAL are installed.";
152 }
153
154 return false; // break and let addingConflictingFqInstance return false
155 });
156 }
157
158 // Remove elements from "list" if p(element) returns true.
159 template <typename List, typename Predicate>
removeIf(List & list,Predicate predicate)160 static void removeIf(List& list, Predicate predicate) {
161 for (auto it = list.begin(); it != list.end();) {
162 if (predicate(*it)) {
163 it = list.erase(it);
164 } else {
165 ++it;
166 }
167 }
168 }
169
removeHals(const std::string & name,size_t majorVer)170 void HalManifest::removeHals(const std::string& name, size_t majorVer) {
171 removeIf(mHals, [&name, majorVer](auto& existingHalPair) {
172 auto& existingHal = existingHalPair.second;
173 if (existingHal.name != name) {
174 return false;
175 }
176 auto& existingVersions = existingHal.versions;
177 removeIf(existingVersions, [majorVer](const auto& existingVersion) {
178 return existingVersion.majorVer == majorVer;
179 });
180 auto& existingManifestInstances = existingHal.mManifestInstances;
181 removeIf(existingManifestInstances, [majorVer](const auto& existingManifestInstance) {
182 return existingManifestInstance.version().majorVer == majorVer;
183 });
184 return existingVersions.empty() && existingManifestInstances.empty();
185 });
186 }
187
add(ManifestHal && halToAdd,std::string * error)188 bool HalManifest::add(ManifestHal&& halToAdd, std::string* error) {
189 if (halToAdd.isOverride()) {
190 if (halToAdd.isDisabledHal()) {
191 // Special syntax when there are no instances at all. Remove all existing HALs
192 // with the given name.
193 mHals.erase(halToAdd.name);
194 }
195 // If there are <version> tags, remove all existing major versions that causes a conflict.
196 for (const Version& versionToAdd : halToAdd.versions) {
197 removeHals(halToAdd.name, versionToAdd.majorVer);
198 }
199 // If there are <fqname> tags, remove all existing major versions that causes a conflict.
200 halToAdd.forEachInstance([this, &halToAdd](const auto& manifestInstanceToAdd) {
201 removeHals(halToAdd.name, manifestInstanceToAdd.version().majorVer);
202 return true; // continue
203 });
204 }
205
206 if (!shouldAdd(halToAdd, error)) {
207 return false;
208 }
209
210 CHECK(addInternal(std::move(halToAdd)) != nullptr);
211 return true;
212 }
213
addAllHals(HalManifest * other,std::string * error)214 bool HalManifest::addAllHals(HalManifest* other, std::string* error) {
215 for (auto& pair : other->mHals) {
216 if (!add(std::move(pair.second), error)) {
217 if (error) {
218 error->insert(0, "HAL \"" + pair.first + "\" has a conflict: ");
219 }
220 return false;
221 }
222 }
223 other->mHals.clear();
224 return true;
225 }
226
shouldAddXmlFile(const ManifestXmlFile & xmlFile) const227 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const {
228 auto existingXmlFiles = getXmlFiles(xmlFile.name());
229 for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) {
230 if (xmlFile.version() == it->second.version()) {
231 return false;
232 }
233 }
234 return true;
235 }
236
getHalNames() const237 std::set<std::string> HalManifest::getHalNames() const {
238 std::set<std::string> names{};
239 for (const auto &hal : mHals) {
240 names.insert(hal.first);
241 }
242 return names;
243 }
244
getHalNamesAndVersions() const245 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
246 std::set<std::string> names{};
247 forEachInstance([&names](const ManifestInstance& e) {
248 switch (e.format()) {
249 case HalFormat::HIDL:
250 [[fallthrough]];
251 case HalFormat::NATIVE:
252 names.insert(toFQNameString(e.package(), e.version()));
253 break;
254 case HalFormat::AIDL:
255 names.insert(e.package() + "@" + aidlVersionToString(e.version()));
256 break;
257 }
258 return true;
259 });
260 return names;
261 }
262
getHidlTransport(const std::string & package,const Version & v,const std::string & interfaceName,const std::string & instanceName) const263 Transport HalManifest::getHidlTransport(const std::string& package, const Version& v,
264 const std::string& interfaceName,
265 const std::string& instanceName) const {
266 Transport transport{Transport::EMPTY};
267 forEachInstanceOfInterface(HalFormat::HIDL, package, v, interfaceName, [&](const auto& e) {
268 if (e.instance() == instanceName) {
269 transport = e.transport();
270 }
271 return transport == Transport::EMPTY; // if not found, continue
272 });
273 if (transport == Transport::EMPTY) {
274 LOG(DEBUG) << "HalManifest::getHidlTransport(" << mType << "): Cannot find "
275 << toFQNameString(package, v, interfaceName, instanceName);
276 }
277 return transport;
278 }
279
forEachInstanceOfVersion(HalFormat format,const std::string & package,const Version & expectVersion,const std::function<bool (const ManifestInstance &)> & func) const280 bool HalManifest::forEachInstanceOfVersion(
281 HalFormat format, const std::string& package, const Version& expectVersion,
282 const std::function<bool(const ManifestInstance&)>& func) const {
283 for (const ManifestHal* hal : getHals(package)) {
284 bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
285 if (manifestInstance.format() == format &&
286 manifestInstance.version().minorAtLeast(expectVersion)) {
287 return func(manifestInstance);
288 }
289 return true;
290 });
291 if (!cont) return false;
292 }
293 return true;
294 }
295
296 // indent = 2, {"foo"} => "foo"
297 // indent = 2, {"foo", "bar"} => "\n foo\n bar";
298 template <typename Container>
multilineIndent(std::ostream & os,size_t indent,const Container & lines)299 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) {
300 if (lines.size() == 1) {
301 os << *lines.begin();
302 return;
303 }
304 for (const auto& line : lines) {
305 os << "\n";
306 for (size_t i = 0; i < indent; ++i) os << " ";
307 os << line;
308 }
309 }
310
311 // For each hal in mat, there must be a hal in manifest that supports this.
checkIncompatibleHals(const CompatibilityMatrix & mat) const312 std::vector<std::string> HalManifest::checkIncompatibleHals(const CompatibilityMatrix& mat) const {
313 std::vector<std::string> ret;
314 for (const MatrixHal &matrixHal : mat.getHals()) {
315 if (matrixHal.optional) {
316 continue;
317 }
318
319 std::set<FqInstance> manifestInstances;
320 std::set<std::string> manifestInstanceDesc;
321 std::set<Version> versions;
322 for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
323 manifestHal->forEachInstance([&](const auto& manifestInstance) {
324 manifestInstances.insert(manifestInstance.getFqInstance());
325 manifestInstanceDesc.insert(manifestInstance.descriptionWithoutPackage());
326 return true;
327 });
328 manifestHal->appendAllVersions(&versions);
329 }
330
331 if (!matrixHal.isCompatible(manifestInstances, versions)) {
332 std::ostringstream oss;
333 oss << matrixHal.name << ":\n required: ";
334 multilineIndent(oss, 8, android::vintf::expandInstances(matrixHal));
335 oss << "\n provided: ";
336 if (manifestInstances.empty()) {
337 multilineIndent(oss, 8, versions);
338 } else {
339 multilineIndent(oss, 8, manifestInstanceDesc);
340 }
341
342 ret.insert(ret.end(), oss.str());
343 }
344 }
345 return ret;
346 }
347
checkUnusedHals(const CompatibilityMatrix & mat,const std::vector<HidlInterfaceMetadata> & hidlMetadata) const348 std::set<std::string> HalManifest::checkUnusedHals(
349 const CompatibilityMatrix& mat, const std::vector<HidlInterfaceMetadata>& hidlMetadata) const {
350 std::multimap<std::string, std::string> childrenMap;
351 for (const auto& child : hidlMetadata) {
352 for (const auto& parent : child.inherited) {
353 childrenMap.emplace(parent, child.name);
354 }
355 }
356
357 std::set<std::string> ret;
358
359 forEachInstance([&ret, &mat, &childrenMap](const auto& manifestInstance) {
360 if (mat.matchInstance(manifestInstance.format(), manifestInstance.package(),
361 manifestInstance.version(), manifestInstance.interface(),
362 manifestInstance.instance())) {
363 // manifestInstance exactly matches an instance in |mat|.
364 return true;
365 }
366 // For HIDL instances, If foo@2.0 inherits from foo@1.0, manifest may contain both, but
367 // matrix may contain only 2.0 if 1.0 is considered deprecated. Hence, if manifestInstance
368 // is 1.0, check all its children in the matrix too.
369 // If there is at least one match, do not consider it unused.
370 if (manifestInstance.format() == HalFormat::HIDL) {
371 auto range =
372 childrenMap.equal_range(manifestInstance.getFqInstance().getFqNameString());
373 for (auto it = range.first; it != range.second; ++it) {
374 details::FQName fqName;
375 CHECK(fqName.setTo(it->second));
376 if (mat.matchInstance(manifestInstance.format(), fqName.package(),
377 fqName.getVersion(), fqName.name(),
378 manifestInstance.instance())) {
379 return true;
380 }
381 }
382 }
383
384 // If no match is found, consider it unused.
385 ret.insert(manifestInstance.description());
386 return true;
387 });
388
389 return ret;
390 }
391
checkApexHals(const CompatibilityMatrix & mat) const392 std::vector<std::string> HalManifest::checkApexHals(const CompatibilityMatrix& mat) const {
393 std::vector<std::string> ret;
394
395 // Validate any APEX-implemented HALs.
396 // Any HALs found within an APEX (hal.updatableViaApex()) must
397 // be declared as updatable-via-apex in the compatibility matrix (matrixHal.updatableViaApex).
398 //
399 // hal.updatableViaApex == <any> AND matrixHal.updatableViaApex == true # VALID
400 // hal.updatableViaApex == <any> AND matrixHal.updatableViaApex == false # INVALID
401 // hal.updatableViaApex == "" (not updatable) # VALID
402 //
403 // Below check for INVALID case (hal.updatableViaApex == <any> && !matrixHal.updatableViaApex)
404
405 for (const auto& hal : getHals()) {
406 bool updatableViaApex =
407 hal.updatableViaApex().has_value() && !hal.updatableViaApex()->empty();
408
409 if (updatableViaApex) {
410 // Check every instance is contained in the matrix with an updatable apex attribute
411 (void)hal.forEachInstance([&mat, &ret](const auto& manifestInstance) {
412 LOG(DEBUG) << "Checking APEX HAL " << manifestInstance.description();
413 bool supported = false;
414 for (const auto& matrixHal : mat.getHals()) {
415 if (matrixHal.updatableViaApex) {
416 // Use false to break out of forEachInstance to indicate a matrix instance
417 // that supports the manifest instance.
418 supported = !matrixHal.forEachInstance([&manifestInstance](
419 const auto& matrixInstance) {
420 if (matrixInstance.isSatisfiedBy(manifestInstance.getFqInstance())) {
421 // break out of forEachInstance
422 return false;
423 }
424 return true;
425 });
426 if (supported) {
427 break;
428 }
429 }
430 }
431 if (!supported) {
432 ret.push_back(manifestInstance.description());
433 }
434 // check all instances
435 return true;
436 });
437 }
438 }
439 return ret;
440 }
441
checkVendorNdkCompatibility(const VendorNdk & matVendorNdk,const std::vector<VendorNdk> & manifestVendorNdk,std::string * error)442 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
443 const std::vector<VendorNdk>& manifestVendorNdk,
444 std::string* error) {
445 // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
446 // tag. Ignore the check for these devices.
447 if (matVendorNdk.version().empty()) {
448 return true;
449 }
450 for (const auto& vndk : manifestVendorNdk) {
451 if (vndk.version() != matVendorNdk.version()) {
452 continue;
453 }
454 // version matches, check libraries
455 std::vector<std::string> diff;
456 std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
457 vndk.libraries().begin(), vndk.libraries().end(),
458 std::inserter(diff, diff.begin()));
459 if (!diff.empty()) {
460 if (error != nullptr) {
461 *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
462 ". These libs are not in framework manifest:";
463 for (const auto& name : diff) {
464 *error += " " + name;
465 }
466 }
467 return false;
468 }
469 return true;
470 }
471
472 // no match is found.
473 if (error != nullptr) {
474 *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
475 "Supported versions in framework manifest are: [";
476 for (const auto& vndk : manifestVendorNdk) {
477 *error += " " + vndk.version();
478 }
479 *error += "]";
480 }
481 return false;
482 }
483
checkSystemSdkCompatibility(const SystemSdk & matSystemSdk,const SystemSdk & manifestSystemSdk,std::string * error)484 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk,
485 const SystemSdk& manifestSystemSdk, std::string* error) {
486 SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk);
487 if (!notSupported.empty()) {
488 if (error) {
489 *error =
490 "The following System SDK versions are required by device "
491 "compatibility matrix but not supported by the framework manifest: [" +
492 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" +
493 base::Join(manifestSystemSdk.versions(), ", ") + "].";
494 }
495 return false;
496 }
497 return true;
498 }
499
checkCompatibility(const CompatibilityMatrix & mat,std::string * error,CheckFlags::Type flags) const500 bool HalManifest::checkCompatibility(const CompatibilityMatrix& mat, std::string* error,
501 CheckFlags::Type flags) const {
502 if (mType == mat.mType) {
503 if (error != nullptr) {
504 *error = "Wrong type; checking " + to_string(mType) + " manifest against "
505 + to_string(mat.mType) + " compatibility matrix";
506 }
507 return false;
508 }
509 auto incompatibleHals = checkIncompatibleHals(mat);
510 if (!incompatibleHals.empty()) {
511 if (error != nullptr) {
512 *error = "HALs incompatible.";
513 if (mat.level() != Level::UNSPECIFIED)
514 *error += " Matrix level = " + to_string(mat.level()) + ".";
515 if (level() != Level::UNSPECIFIED)
516 *error += " Manifest level = " + to_string(level()) + ".";
517 *error += " The following requirements are not met:\n";
518 for (const auto& e : incompatibleHals) {
519 *error += e + "\n";
520 }
521 }
522 return false;
523 }
524 if (mType == SchemaType::FRAMEWORK) {
525 if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
526 return false;
527 }
528
529 if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) {
530 return false;
531 }
532 } else if (mType == SchemaType::DEVICE) {
533 bool sepolicyMatch = false;
534 for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
535 if (range.supportedBy(device.mSepolicyVersion)) {
536 sepolicyMatch = true;
537 break;
538 }
539 }
540 if (!sepolicyMatch) {
541 if (error != nullptr) {
542 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
543 + " doesn't satisify the requirements.";
544 }
545 return false;
546 }
547
548 // Not using inferredKernelLevel() to preserve the legacy behavior if <kernel> does not have
549 // level attribute.
550 // Note that shouldCheckKernelCompatibility() only returns true on host, because the
551 // on-device HalManifest does not have kernel version set. On the device, kernel information
552 // is retrieved from RuntimeInfo.
553 Level kernelTagLevel = kernel()->level();
554 if (flags.isKernelEnabled() && shouldCheckKernelCompatibility() &&
555 kernel()
556 ->getMatchedKernelRequirements(mat.framework.mKernels, kernelTagLevel, error)
557 .empty()) {
558 return false;
559 }
560 // Check APEX-implemented HALs are supported in matrix
561 auto unsupportedApexHals = checkApexHals(mat);
562 if (!unsupportedApexHals.empty()) {
563 if (error != nullptr) {
564 *error = "APEX-implemented HALs not supported in compatibility matrix:\n";
565 for (auto const& n : unsupportedApexHals) {
566 *error += "\n" + n;
567 }
568 }
569 return false;
570 }
571 }
572
573 return true;
574 }
575
shouldCheckKernelCompatibility() const576 bool HalManifest::shouldCheckKernelCompatibility() const {
577 return kernel().has_value() && kernel()->version() != KernelVersion{};
578 }
579
generateCompatibleMatrix(bool optional) const580 CompatibilityMatrix HalManifest::generateCompatibleMatrix(bool optional) const {
581 CompatibilityMatrix matrix;
582
583 std::set<std::tuple<HalFormat, std::string, Version, std::string, std::string>> instances;
584
585 forEachInstance([&matrix, &instances, optional](const ManifestInstance& e) {
586 auto&& [it, added] =
587 instances.emplace(e.format(), e.package(), e.version(), e.interface(), e.instance());
588 if (!added) {
589 return true;
590 }
591
592 matrix.add(MatrixHal{
593 .format = e.format(),
594 .name = e.package(),
595 .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}},
596 .optional = optional,
597 .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}});
598 return true;
599 });
600 if (mType == SchemaType::FRAMEWORK) {
601 matrix.mType = SchemaType::DEVICE;
602 // VNDK does not need to be added for compatibility
603 } else if (mType == SchemaType::DEVICE) {
604 matrix.mType = SchemaType::FRAMEWORK;
605 matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
606 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
607 }
608
609 return matrix;
610 }
611
fetchAllInformation(const FileSystem * fileSystem,const std::string & path,std::string * error)612 status_t HalManifest::fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
613 std::string* error) {
614 return details::fetchAllInformation(fileSystem, path, this, error);
615 }
616
type() const617 SchemaType HalManifest::type() const {
618 return mType;
619 }
620
setType(SchemaType type)621 void HalManifest::setType(SchemaType type) {
622 mType = type;
623 }
624
level() const625 Level HalManifest::level() const {
626 return mLevel;
627 }
628
sepolicyVersion() const629 const Version &HalManifest::sepolicyVersion() const {
630 CHECK(mType == SchemaType::DEVICE);
631 return device.mSepolicyVersion;
632 }
633
vendorNdks() const634 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
635 CHECK(mType == SchemaType::FRAMEWORK);
636 return framework.mVendorNdks;
637 }
638
getXmlFilePath(const std::string & xmlFileName,const Version & version) const639 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
640 const Version& version) const {
641 using std::literals::string_literals::operator""s;
642 auto range = getXmlFiles(xmlFileName);
643 for (auto it = range.first; it != range.second; ++it) {
644 const ManifestXmlFile& manifestXmlFile = it->second;
645 if (manifestXmlFile.version() == version) {
646 if (!manifestXmlFile.overriddenPath().empty()) {
647 return manifestXmlFile.overriddenPath();
648 }
649 return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
650 xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
651 std::to_string(version.minorVer) + ".xml";
652 }
653 }
654 return "";
655 }
656
operator ==(const HalManifest & lft,const HalManifest & rgt)657 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
658 // ignore fileName().
659 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
660 lft.mXmlFiles == rgt.mXmlFiles &&
661 (lft.mType != SchemaType::DEVICE ||
662 (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion &&
663 lft.device.mKernel == rgt.device.mKernel)) &&
664 (lft.mType != SchemaType::FRAMEWORK ||
665 (
666 #pragma clang diagnostic push
667 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
668 lft.framework.mVndks == rgt.framework.mVndks &&
669 #pragma clang diagnostic pop
670 lft.framework.mVendorNdks == rgt.framework.mVendorNdks &&
671 lft.framework.mSystemSdk == rgt.framework.mSystemSdk));
672 }
673
674 // 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) const675 std::set<std::string> HalManifest::getInstances(HalFormat format, const std::string& package,
676 const Version& version,
677 const std::string& interfaceName) const {
678 std::set<std::string> ret;
679 (void)forEachInstanceOfInterface(format, package, version, interfaceName,
680 [&ret](const auto& e) {
681 ret.insert(e.instance());
682 return true;
683 });
684 return ret;
685 }
686
687 // Return whether instance is in getInstances(...).
hasInstance(HalFormat format,const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const688 bool HalManifest::hasInstance(HalFormat format, const std::string& package, const Version& version,
689 const std::string& interfaceName, const std::string& instance) const {
690 bool found = false;
691 (void)forEachInstanceOfInterface(format, package, version, interfaceName,
692 [&found, &instance](const auto& e) {
693 found |= (instance == e.instance());
694 return !found; // if not found, continue
695 });
696 return found;
697 }
getHidlInstances(const std::string & package,const Version & version,const std::string & interfaceName) const698 std::set<std::string> HalManifest::getHidlInstances(const std::string& package,
699 const Version& version,
700 const std::string& interfaceName) const {
701 return getInstances(HalFormat::HIDL, package, version, interfaceName);
702 }
703
getAidlInstances(const std::string & package,const std::string & interfaceName) const704 std::set<std::string> HalManifest::getAidlInstances(const std::string& package,
705 const std::string& interfaceName) const {
706 return getAidlInstances(package, 0, interfaceName);
707 }
708
getAidlInstances(const std::string & package,size_t version,const std::string & interfaceName) const709 std::set<std::string> HalManifest::getAidlInstances(const std::string& package, size_t version,
710 const std::string& interfaceName) const {
711 return getInstances(HalFormat::AIDL, package, {details::kFakeAidlMajorVersion, version},
712 interfaceName);
713 }
714
hasHidlInstance(const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const715 bool HalManifest::hasHidlInstance(const std::string& package, const Version& version,
716 const std::string& interfaceName,
717 const std::string& instance) const {
718 return hasInstance(HalFormat::HIDL, package, version, interfaceName, instance);
719 }
720
hasAidlInstance(const std::string & package,const std::string & interface,const std::string & instance) const721 bool HalManifest::hasAidlInstance(const std::string& package, const std::string& interface,
722 const std::string& instance) const {
723 return hasAidlInstance(package, 0, interface, instance);
724 }
725
hasAidlInstance(const std::string & package,size_t version,const std::string & interface,const std::string & instance) const726 bool HalManifest::hasAidlInstance(const std::string& package, size_t version,
727 const std::string& interface, const std::string& instance) const {
728 return hasInstance(HalFormat::AIDL, package, {details::kFakeAidlMajorVersion, version},
729 interface, instance);
730 }
731
insertInstance(const FqInstance & fqInstance,Transport transport,Arch arch,HalFormat format,std::string * error)732 bool HalManifest::insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch,
733 HalFormat format, std::string* error) {
734 for (ManifestHal& hal : getHals()) {
735 if (hal.name == fqInstance.getPackage() && hal.format == format &&
736 hal.transport() == transport && hal.arch() == arch) {
737 return hal.insertInstance(fqInstance, error);
738 }
739 }
740
741 ManifestHal hal;
742 hal.name = fqInstance.getPackage();
743 hal.format = format;
744 hal.transportArch = TransportArch(transport, arch);
745 if (!hal.insertInstance(fqInstance, error)) return false;
746 return add(std::move(hal), error);
747 }
748
empty() const749 bool HalManifest::empty() const {
750 HalManifest emptyManifest;
751 emptyManifest.setType(type());
752 return (*this) == emptyManifest;
753 }
754
kernel() const755 const std::optional<KernelInfo>& HalManifest::kernel() const {
756 return device.mKernel;
757 }
758
mergeKernel(std::optional<KernelInfo> * other,std::string * error)759 bool HalManifest::mergeKernel(std::optional<KernelInfo>* other, std::string* error) {
760 if (!other->has_value()) {
761 return true;
762 }
763
764 if (device.mKernel.has_value()) {
765 if (!device.mKernel->merge(&**other, error)) {
766 return false;
767 }
768 } else {
769 device.mKernel = std::move(*other);
770 }
771
772 *other = std::nullopt;
773 return true;
774 }
775
addAll(HalManifest * other,std::string * error)776 bool HalManifest::addAll(HalManifest* other, std::string* error) {
777 if (type() != other->type()) {
778 if (error) {
779 *error = "Cannot add a " + to_string(other->type()) + " manifest to a " +
780 to_string(type()) + " manifest";
781 }
782 return false;
783 }
784
785 if (!addAllHals(other, error)) {
786 return false;
787 }
788
789 if (!addAllXmlFiles(other, error)) {
790 return false;
791 }
792
793 if (!mergeField(&mLevel, &other->mLevel, Level::UNSPECIFIED)) {
794 if (error) {
795 *error = "Conflicting target-level: " + to_string(level()) + " vs. " +
796 to_string(other->level());
797 }
798 return false;
799 }
800
801 if (type() == SchemaType::DEVICE) {
802 if (!mergeField(&device.mSepolicyVersion, &other->device.mSepolicyVersion)) {
803 if (error) {
804 *error = "Conflicting sepolicy version: " + to_string(sepolicyVersion()) + " vs. " +
805 to_string(other->sepolicyVersion());
806 }
807 return false;
808 }
809
810 if (!mergeKernel(&other->device.mKernel, error)) {
811 return false;
812 }
813 } else if (type() == SchemaType::FRAMEWORK) {
814 #pragma clang diagnostic push
815 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
816 framework.mVndks.insert(framework.mVndks.end(), other->framework.mVndks.begin(),
817 other->framework.mVndks.end());
818 other->framework.mVndks.clear();
819 #pragma clang diagnostic pop
820
821 framework.mVendorNdks.insert(framework.mVendorNdks.end(),
822 other->framework.mVendorNdks.begin(),
823 other->framework.mVendorNdks.end());
824 other->framework.mVendorNdks.clear();
825
826 framework.mSystemSdk.addAll(&other->framework.mSystemSdk);
827 } else {
828 LOG(FATAL) << "unknown SchemaType: "
829 << static_cast<std::underlying_type_t<SchemaType>>(type());
830 }
831
832 if (!other->empty()) {
833 if (error) {
834 *error =
835 "Cannot add another manifest because it contains extraneous entries that "
836 "are not recognized.";
837 }
838 return false;
839 }
840
841 return true;
842 }
843
inferredKernelLevel() const844 Level HalManifest::inferredKernelLevel() const {
845 if (kernel().has_value()) {
846 if (kernel()->level() != Level::UNSPECIFIED) {
847 return kernel()->level();
848 }
849 }
850 // As a special case, for devices launching with R and above, also infer from <manifest>.level.
851 // Devices launching before R may leave kernel level unspecified to use legacy kernel
852 // matching behavior; see KernelInfo::getMatchedKernelRequirements.
853 if (level() >= Level::R) {
854 return level();
855 }
856 return Level::UNSPECIFIED;
857 }
858
859 } // namespace vintf
860 } // namespace android
861