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 
forEachNativeInstance(const std::string & package,const std::function<bool (const ManifestInstance &)> & func) const296 bool HalManifest::forEachNativeInstance(
297     const std::string& package, const std::function<bool(const ManifestInstance&)>& func) const {
298     for (const ManifestHal* hal : getHals(package)) {
299         bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
300             if (manifestInstance.format() == HalFormat::NATIVE) {
301                 return func(manifestInstance);
302             }
303             return true;
304         });
305         if (!cont) return false;
306     }
307     return true;
308 }
309 
310 // indent = 2, {"foo"} => "foo"
311 // indent = 2, {"foo", "bar"} => "\n  foo\n  bar";
312 template <typename Container>
multilineIndent(std::ostream & os,size_t indent,const Container & lines)313 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) {
314     if (lines.size() == 1) {
315         os << *lines.begin();
316         return;
317     }
318     for (const auto& line : lines) {
319         os << "\n";
320         for (size_t i = 0; i < indent; ++i) os << " ";
321         os << line;
322     }
323 }
324 
325 // For each hal in mat, there must be a hal in manifest that supports this.
checkIncompatibleHals(const CompatibilityMatrix & mat) const326 std::vector<std::string> HalManifest::checkIncompatibleHals(const CompatibilityMatrix& mat) const {
327     std::vector<std::string> ret;
328     for (const MatrixHal &matrixHal : mat.getHals()) {
329         if (matrixHal.optional) {
330             continue;
331         }
332 
333         std::set<FqInstance> manifestInstances;
334         std::set<std::string> manifestInstanceDesc;
335         std::set<Version> versions;
336         for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
337             manifestHal->forEachInstance([&](const auto& manifestInstance) {
338                 manifestInstances.insert(manifestInstance.getFqInstance());
339                 manifestInstanceDesc.insert(manifestInstance.descriptionWithoutPackage());
340                 return true;
341             });
342             manifestHal->appendAllVersions(&versions);
343         }
344 
345         if (!matrixHal.isCompatible(manifestInstances, versions)) {
346             std::ostringstream oss;
347             oss << matrixHal.name << ":\n    required: ";
348             multilineIndent(oss, 8, android::vintf::expandInstances(matrixHal));
349             oss << "\n    provided: ";
350             if (manifestInstances.empty()) {
351                 multilineIndent(oss, 8, versions);
352             } else {
353                 multilineIndent(oss, 8, manifestInstanceDesc);
354             }
355 
356             ret.insert(ret.end(), oss.str());
357         }
358     }
359     return ret;
360 }
361 
checkUnusedHals(const CompatibilityMatrix & mat,const std::vector<HidlInterfaceMetadata> & hidlMetadata) const362 std::set<std::string> HalManifest::checkUnusedHals(
363     const CompatibilityMatrix& mat, const std::vector<HidlInterfaceMetadata>& hidlMetadata) const {
364     std::multimap<std::string, std::string> childrenMap;
365     for (const auto& child : hidlMetadata) {
366         for (const auto& parent : child.inherited) {
367             childrenMap.emplace(parent, child.name);
368         }
369     }
370 
371     std::set<std::string> ret;
372 
373     forEachInstance([&ret, &mat, &childrenMap](const auto& manifestInstance) {
374         if (mat.matchInstance(manifestInstance.format(), manifestInstance.package(),
375                               manifestInstance.version(), manifestInstance.interface(),
376                               manifestInstance.instance())) {
377             // manifestInstance exactly matches an instance in |mat|.
378             return true;
379         }
380         // For HIDL instances, If foo@2.0 inherits from foo@1.0, manifest may contain both, but
381         // matrix may contain only 2.0 if 1.0 is considered deprecated. Hence, if manifestInstance
382         // is 1.0, check all its children in the matrix too.
383         // If there is at least one match, do not consider it unused.
384         if (manifestInstance.format() == HalFormat::HIDL) {
385             auto range =
386                 childrenMap.equal_range(manifestInstance.getFqInstance().getFqNameString());
387             for (auto it = range.first; it != range.second; ++it) {
388                 details::FQName fqName;
389                 CHECK(fqName.setTo(it->second));
390                 if (mat.matchInstance(manifestInstance.format(), fqName.package(),
391                                       fqName.getVersion(), fqName.name(),
392                                       manifestInstance.instance())) {
393                     return true;
394                 }
395             }
396         }
397 
398         // If no match is found, consider it unused.
399         ret.insert(manifestInstance.description());
400         return true;
401     });
402 
403     return ret;
404 }
405 
checkVendorNdkCompatibility(const VendorNdk & matVendorNdk,const std::vector<VendorNdk> & manifestVendorNdk,std::string * error)406 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
407                                         const std::vector<VendorNdk>& manifestVendorNdk,
408                                         std::string* error) {
409     // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
410     // tag. Ignore the check for these devices.
411     // VNDK is no longer a dependency for vendor version 35 and beyond. On these images,
412     // <vendor-ndk> is also empty.
413     if (matVendorNdk.version().empty()) {
414         return true;
415     }
416     for (const auto& vndk : manifestVendorNdk) {
417         if (vndk.version() != matVendorNdk.version()) {
418             continue;
419         }
420         // version matches, check libraries
421         std::vector<std::string> diff;
422         std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
423                             vndk.libraries().begin(), vndk.libraries().end(),
424                             std::inserter(diff, diff.begin()));
425         if (!diff.empty()) {
426             if (error != nullptr) {
427                 *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
428                          ". These libs are not in framework manifest:";
429                 for (const auto& name : diff) {
430                     *error += " " + name;
431                 }
432             }
433             return false;
434         }
435         return true;
436     }
437 
438     // no match is found.
439     if (error != nullptr) {
440         *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
441                  "Supported versions in framework manifest are: [";
442         for (const auto& vndk : manifestVendorNdk) {
443             *error += " " + vndk.version();
444         }
445         *error += "]";
446     }
447     return false;
448 }
449 
checkSystemSdkCompatibility(const SystemSdk & matSystemSdk,const SystemSdk & manifestSystemSdk,std::string * error)450 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk,
451                                         const SystemSdk& manifestSystemSdk, std::string* error) {
452     SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk);
453     if (!notSupported.empty()) {
454         if (error) {
455             *error =
456                 "The following System SDK versions are required by device "
457                 "compatibility matrix but not supported by the framework manifest: [" +
458                 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" +
459                 base::Join(manifestSystemSdk.versions(), ", ") + "].";
460         }
461         return false;
462     }
463     return true;
464 }
465 
checkCompatibility(const CompatibilityMatrix & mat,std::string * error,CheckFlags::Type flags) const466 bool HalManifest::checkCompatibility(const CompatibilityMatrix& mat, std::string* error,
467                                      CheckFlags::Type flags) const {
468     if (mType == mat.mType) {
469         if (error != nullptr) {
470             *error = "Wrong type; checking " + to_string(mType) + " manifest against "
471                     + to_string(mat.mType) + " compatibility matrix";
472         }
473         return false;
474     }
475     auto incompatibleHals = checkIncompatibleHals(mat);
476     if (!incompatibleHals.empty()) {
477         if (error != nullptr) {
478             *error = "HALs incompatible.";
479             if (mat.level() != Level::UNSPECIFIED)
480                 *error += " Matrix level = " + to_string(mat.level()) + ".";
481             if (level() != Level::UNSPECIFIED)
482                 *error += " Manifest level = " + to_string(level()) + ".";
483             *error += " The following requirements are not met:\n";
484             for (const auto& e : incompatibleHals) {
485                 *error += e + "\n";
486             }
487         }
488         return false;
489     }
490     if (mType == SchemaType::FRAMEWORK) {
491         if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
492             return false;
493         }
494 
495         if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) {
496             return false;
497         }
498     } else if (mType == SchemaType::DEVICE) {
499         bool sepolicyMatch = false;
500         for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
501             if (range.supportedBy(device.mSepolicyVersion)) {
502                 sepolicyMatch = true;
503                 break;
504             }
505         }
506         if (!sepolicyMatch) {
507             if (error != nullptr) {
508                 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
509                         + " doesn't satisify the requirements.";
510             }
511             return false;
512         }
513 
514         // Not using inferredKernelLevel() to preserve the legacy behavior if <kernel> does not have
515         // level attribute.
516         // Note that shouldCheckKernelCompatibility() only returns true on host, because the
517         // on-device HalManifest does not have kernel version set. On the device, kernel information
518         // is retrieved from RuntimeInfo.
519         Level kernelTagLevel = kernel()->level();
520         if (flags.isKernelEnabled() && shouldCheckKernelCompatibility() &&
521             kernel()
522                 ->getMatchedKernelRequirements(mat.framework.mKernels, kernelTagLevel, error)
523                 .empty()) {
524             return false;
525         }
526     }
527 
528     return true;
529 }
530 
shouldCheckKernelCompatibility() const531 bool HalManifest::shouldCheckKernelCompatibility() const {
532     return kernel().has_value() && kernel()->version() != KernelVersion{};
533 }
534 
generateCompatibleMatrix(bool optional) const535 CompatibilityMatrix HalManifest::generateCompatibleMatrix(bool optional) const {
536     CompatibilityMatrix matrix;
537 
538     std::set<std::tuple<HalFormat, std::string, Version, std::string, std::string>> instances;
539 
540     forEachInstance([&matrix, &instances, optional](const ManifestInstance& e) {
541         auto&& [it, added] =
542             instances.emplace(e.format(), e.package(), e.version(), e.interface(), e.instance());
543         if (!added) {
544             return true;
545         }
546 
547         matrix.add(MatrixHal{
548             .format = e.format(),
549             .name = e.package(),
550             .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}},
551             .optional = optional,
552             .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}});
553         return true;
554     });
555     if (mType == SchemaType::FRAMEWORK) {
556         matrix.mType = SchemaType::DEVICE;
557         // VNDK does not need to be added for compatibility
558     } else if (mType == SchemaType::DEVICE) {
559         matrix.mType = SchemaType::FRAMEWORK;
560         matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
561                 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
562     }
563 
564     return matrix;
565 }
566 
fetchAllInformation(const FileSystem * fileSystem,const std::string & path,std::string * error)567 status_t HalManifest::fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
568                                           std::string* error) {
569     return details::fetchAllInformation(fileSystem, path, this, error);
570 }
571 
type() const572 SchemaType HalManifest::type() const {
573     return mType;
574 }
575 
setType(SchemaType type)576 void HalManifest::setType(SchemaType type) {
577     mType = type;
578 }
579 
level() const580 Level HalManifest::level() const {
581     return mLevel;
582 }
583 
sepolicyVersion() const584 const SepolicyVersion& HalManifest::sepolicyVersion() const {
585     CHECK(mType == SchemaType::DEVICE);
586     return device.mSepolicyVersion;
587 }
588 
vendorNdks() const589 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
590     CHECK(mType == SchemaType::FRAMEWORK);
591     return framework.mVendorNdks;
592 }
593 
getXmlFilePath(const std::string & xmlFileName,const Version & version) const594 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
595                                         const Version& version) const {
596     using std::literals::string_literals::operator""s;
597     auto range = getXmlFiles(xmlFileName);
598     for (auto it = range.first; it != range.second; ++it) {
599         const ManifestXmlFile& manifestXmlFile = it->second;
600         if (manifestXmlFile.version() == version) {
601             if (!manifestXmlFile.overriddenPath().empty()) {
602                 return manifestXmlFile.overriddenPath();
603             }
604             return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
605                    xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
606                    std::to_string(version.minorVer) + ".xml";
607         }
608     }
609     return "";
610 }
611 
operator ==(const HalManifest & lft,const HalManifest & rgt)612 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
613     // ignore fileName().
614     return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
615            lft.mXmlFiles == rgt.mXmlFiles &&
616            (lft.mType != SchemaType::DEVICE ||
617             (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion &&
618              lft.device.mKernel == rgt.device.mKernel)) &&
619            (lft.mType != SchemaType::FRAMEWORK ||
620             (
621 #pragma clang diagnostic push
622 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
623                 lft.framework.mVndks == rgt.framework.mVndks &&
624 #pragma clang diagnostic pop
625                 lft.framework.mVendorNdks == rgt.framework.mVendorNdks &&
626                 lft.framework.mSystemSdk == rgt.framework.mSystemSdk));
627 }
628 
629 // 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) const630 std::set<std::string> HalManifest::getInstances(HalFormat format, const std::string& package,
631                                                 const Version& version,
632                                                 const std::string& interfaceName) const {
633     std::set<std::string> ret;
634     (void)forEachInstanceOfInterface(format, package, version, interfaceName,
635                                      [&ret](const auto& e) {
636                                          ret.insert(e.instance());
637                                          return true;
638                                      });
639     return ret;
640 }
641 
642 // Return whether instance is in getInstances(...).
hasInstance(HalFormat format,const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const643 bool HalManifest::hasInstance(HalFormat format, const std::string& package, const Version& version,
644                               const std::string& interfaceName, const std::string& instance) const {
645     bool found = false;
646     (void)forEachInstanceOfInterface(format, package, version, interfaceName,
647                                      [&found, &instance](const auto& e) {
648                                          found |= (instance == e.instance());
649                                          return !found;  // if not found, continue
650                                      });
651     return found;
652 }
getHidlInstances(const std::string & package,const Version & version,const std::string & interfaceName) const653 std::set<std::string> HalManifest::getHidlInstances(const std::string& package,
654                                                     const Version& version,
655                                                     const std::string& interfaceName) const {
656     return getInstances(HalFormat::HIDL, package, version, interfaceName);
657 }
658 
getAidlInstances(const std::string & package,const std::string & interfaceName) const659 std::set<std::string> HalManifest::getAidlInstances(const std::string& package,
660                                                     const std::string& interfaceName) const {
661     return getAidlInstances(package, 0, interfaceName);
662 }
663 
getAidlInstances(const std::string & package,size_t version,const std::string & interfaceName) const664 std::set<std::string> HalManifest::getAidlInstances(const std::string& package, size_t version,
665                                                     const std::string& interfaceName) const {
666     return getInstances(HalFormat::AIDL, package, {details::kFakeAidlMajorVersion, version},
667                         interfaceName);
668 }
669 
getNativeInstances(const std::string & package) const670 std::set<std::string> HalManifest::getNativeInstances(const std::string& package) const {
671     std::set<std::string> instances;
672     forEachNativeInstance(package, [&](const auto& inst) {
673         instances.insert(inst.instance());
674         return true;
675     });
676     return instances;
677 }
678 
hasHidlInstance(const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const679 bool HalManifest::hasHidlInstance(const std::string& package, const Version& version,
680                                   const std::string& interfaceName,
681                                   const std::string& instance) const {
682     return hasInstance(HalFormat::HIDL, package, version, interfaceName, instance);
683 }
684 
hasAidlInstance(const std::string & package,const std::string & interface,const std::string & instance) const685 bool HalManifest::hasAidlInstance(const std::string& package, const std::string& interface,
686                                   const std::string& instance) const {
687     return hasAidlInstance(package, 0, interface, instance);
688 }
689 
hasAidlInstance(const std::string & package,size_t version,const std::string & interface,const std::string & instance) const690 bool HalManifest::hasAidlInstance(const std::string& package, size_t version,
691                                   const std::string& interface, const std::string& instance) const {
692     return hasInstance(HalFormat::AIDL, package, {details::kFakeAidlMajorVersion, version},
693                        interface, instance);
694 }
695 
hasNativeInstance(const std::string & package,const std::string & instance) const696 bool HalManifest::hasNativeInstance(const std::string& package, const std::string& instance) const {
697     bool found = false;
698     forEachNativeInstance(package, [&](const auto& inst) {
699         found |= inst.instance() == instance;
700         return !found;  // continue if not found
701     });
702     return found;
703 }
704 
insertInstance(const FqInstance & fqInstance,Transport transport,Arch arch,HalFormat format,std::string * error)705 bool HalManifest::insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch,
706                                  HalFormat format, std::string* error) {
707     for (ManifestHal& hal : getHals()) {
708         if (hal.name == fqInstance.getPackage() && hal.format == format &&
709             hal.transport() == transport && hal.arch() == arch) {
710             return hal.insertInstance(fqInstance, error);
711         }
712     }
713 
714     ManifestHal hal;
715     hal.name = fqInstance.getPackage();
716     hal.format = format;
717     hal.transportArch = TransportArch(transport, arch);
718     if (!hal.insertInstance(fqInstance, error)) return false;
719     return add(std::move(hal), error);
720 }
721 
empty() const722 bool HalManifest::empty() const {
723     HalManifest emptyManifest;
724     emptyManifest.setType(type());
725     return (*this) == emptyManifest;
726 }
727 
kernel() const728 const std::optional<KernelInfo>& HalManifest::kernel() const {
729     return device.mKernel;
730 }
731 
mergeKernel(std::optional<KernelInfo> * other,std::string * error)732 bool HalManifest::mergeKernel(std::optional<KernelInfo>* other, std::string* error) {
733     if (!other->has_value()) {
734         return true;
735     }
736 
737     if (device.mKernel.has_value()) {
738         if (!device.mKernel->merge(&**other, error)) {
739             return false;
740         }
741     } else {
742         device.mKernel = std::move(*other);
743     }
744 
745     *other = std::nullopt;
746     return true;
747 }
748 
addAll(HalManifest * other,std::string * error)749 bool HalManifest::addAll(HalManifest* other, std::string* error) {
750     if (type() != other->type()) {
751         if (error) {
752             *error = "Cannot add a " + to_string(other->type()) + " manifest to a " +
753                      to_string(type()) + " manifest";
754         }
755         return false;
756     }
757 
758     if (!addAllHals(other, error)) {
759         return false;
760     }
761 
762     if (!addAllXmlFiles(other, error)) {
763         return false;
764     }
765 
766     if (!mergeField(&mLevel, &other->mLevel, Level::UNSPECIFIED)) {
767         if (error) {
768             *error = "Conflicting target-level: " + to_string(level()) + " vs. " +
769                      to_string(other->level());
770         }
771         return false;
772     }
773 
774     if (type() == SchemaType::DEVICE) {
775         if (!mergeField(&device.mSepolicyVersion, &other->device.mSepolicyVersion)) {
776             if (error) {
777                 *error = "Conflicting sepolicy version: " + to_string(sepolicyVersion()) + " vs. " +
778                          to_string(other->sepolicyVersion());
779             }
780             return false;
781         }
782 
783         if (!mergeKernel(&other->device.mKernel, error)) {
784             return false;
785         }
786     } else if (type() == SchemaType::FRAMEWORK) {
787 #pragma clang diagnostic push
788 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
789         framework.mVndks.insert(framework.mVndks.end(), other->framework.mVndks.begin(),
790                                 other->framework.mVndks.end());
791         other->framework.mVndks.clear();
792 #pragma clang diagnostic pop
793 
794         framework.mVendorNdks.insert(framework.mVendorNdks.end(),
795                                      other->framework.mVendorNdks.begin(),
796                                      other->framework.mVendorNdks.end());
797         other->framework.mVendorNdks.clear();
798 
799         framework.mSystemSdk.addAll(&other->framework.mSystemSdk);
800     } else {
801         LOG(FATAL) << "unknown SchemaType: "
802                    << static_cast<std::underlying_type_t<SchemaType>>(type());
803     }
804 
805     if (!other->empty()) {
806         if (error) {
807             *error =
808                 "Cannot add another manifest because it contains extraneous entries that "
809                 "are not recognized.";
810         }
811         return false;
812     }
813 
814     return true;
815 }
816 
inferredKernelLevel() const817 Level HalManifest::inferredKernelLevel() const {
818     if (kernel().has_value()) {
819         if (kernel()->level() != Level::UNSPECIFIED) {
820             return kernel()->level();
821         }
822     }
823     // As a special case, for devices launching with R and above, also infer from <manifest>.level.
824     // Devices launching before R may leave kernel level unspecified to use legacy kernel
825     // matching behavior; see KernelInfo::getMatchedKernelRequirements.
826     if (level() >= Level::R) {
827         return level();
828     }
829     return Level::UNSPECIFIED;
830 }
831 
832 } // namespace vintf
833 } // namespace android
834