xref: /aosp_15_r20/system/libvintf/HalManifest.cpp (revision 70a7ec852fcefd15a4fb57f8f183a8b1c3aacb08)
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     std::map<std::string, std::tuple<const ManifestHal*, ManifestInstance>> existingAccessors;
115     for (auto it = existingHals.first; it != existingHals.second; ++it) {
116         const ManifestHal& existingHal = it->second;
117         bool success = existingHal.forEachInstance(
118             [&existingHal, &existing, &existingAccessors](const auto& manifestInstance) {
119                 auto versionZero = manifestInstance.version().withMinor(0);
120                 auto key = manifestInstance.withVersion(versionZero).getFqInstance();
121                 // Assume integrity on existingHals, so no check on emplace().second
122                 existing.emplace(key, std::make_tuple(&existingHal, manifestInstance));
123                 if (auto accessor = manifestInstance.accessor(); accessor.has_value()) {
124                     existingAccessors.emplace(accessor.value(),
125                                               std::make_tuple(&existingHal, manifestInstance));
126                 }
127                 return true;  // continue
128             });
129         if (!success) {
130             return false;
131         }
132     }
133     return halToAdd.forEachInstance([&halToAdd, &existing, &existingAccessors,
134                                      &error](const auto& manifestInstanceToAdd) {
135         auto constructErrorMessage = [&halToAdd, &manifestInstanceToAdd](
136                                          const auto& existingManifestInstance,
137                                          const auto& existingHal) {
138             std::string errorMsg = existingManifestInstance.descriptionWithoutPackage();
139             if (!existingHal->fileName().empty()) {
140                 errorMsg += " (from " + existingHal->fileName() + ")";
141             }
142             errorMsg += " vs. " + manifestInstanceToAdd.descriptionWithoutPackage();
143             if (!halToAdd.fileName().empty()) {
144                 errorMsg += " (from " + halToAdd.fileName() + ")";
145             }
146             return errorMsg;
147         };
148 
149         auto versionZero = manifestInstanceToAdd.version().withMinor(0);
150         auto key = manifestInstanceToAdd.withVersion(versionZero).getFqInstance();
151 
152         // Check duplicate FqInstance.
153         auto&& [existingIt, inserted] =
154             existing.emplace(key, std::make_tuple(&halToAdd, manifestInstanceToAdd));
155         if (!inserted) {
156             if (error) {
157                 auto&& [existingHal, existingManifestInstance] = existingIt->second;
158                 *error = "Conflicting FqInstance: ";
159                 *error += constructErrorMessage(existingManifestInstance, existingHal);
160                 *error +=
161                     ". Check whether or not multiple modules providing the same HAL are installed.";
162             }
163             return false;  // break and let addingConflictingFqInstance return false
164         }
165 
166         // Check duplicate accessor.
167         auto accessor = manifestInstanceToAdd.accessor();
168         if (!accessor.has_value()) {
169             return true;
170         }
171         auto&& [existingAccessorIt, insertedAccessor] = existingAccessors.emplace(
172             accessor.value(), std::make_tuple(&halToAdd, manifestInstanceToAdd));
173         if (insertedAccessor) {
174             return true;
175         }
176         if (error) {
177             auto&& [existingHal, existingManifestInstance] = existingAccessorIt->second;
178             *error = "Conflicting Accessor: ";
179             *error += constructErrorMessage(existingManifestInstance, existingHal);
180             *error +=
181                 ". Check whether or not multiple modules providing the same accessor are "
182                 "installed.";
183         }
184         return false;  // break and let addingConflictingFqInstance return false
185     });
186 }
187 
188 // Remove elements from "list" if p(element) returns true.
189 template <typename List, typename Predicate>
removeIf(List & list,Predicate predicate)190 static void removeIf(List& list, Predicate predicate) {
191     for (auto it = list.begin(); it != list.end();) {
192         if (predicate(*it)) {
193             it = list.erase(it);
194         } else {
195             ++it;
196         }
197     }
198 }
199 
removeHals(const std::string & name,size_t majorVer)200 void HalManifest::removeHals(const std::string& name, size_t majorVer) {
201     removeIf(mHals, [&name, majorVer](auto& existingHalPair) {
202         auto& existingHal = existingHalPair.second;
203         if (existingHal.name != name) {
204             return false;
205         }
206         auto& existingVersions = existingHal.versions;
207         removeIf(existingVersions, [majorVer](const auto& existingVersion) {
208             return existingVersion.majorVer == majorVer;
209         });
210         auto& existingManifestInstances = existingHal.mManifestInstances;
211         removeIf(existingManifestInstances, [majorVer](const auto& existingManifestInstance) {
212             return existingManifestInstance.version().majorVer == majorVer;
213         });
214         return existingVersions.empty() && existingManifestInstances.empty();
215     });
216 }
217 
add(ManifestHal && halToAdd,std::string * error)218 bool HalManifest::add(ManifestHal&& halToAdd, std::string* error) {
219     if (halToAdd.isOverride()) {
220         if (halToAdd.isDisabledHal()) {
221             // Special syntax when there are no instances at all. Remove all existing HALs
222             // with the given name.
223             mHals.erase(halToAdd.name);
224         }
225         // If there are <version> tags, remove all existing major versions that causes a conflict.
226         for (const Version& versionToAdd : halToAdd.versions) {
227             removeHals(halToAdd.name, versionToAdd.majorVer);
228         }
229         // If there are <fqname> tags, remove all existing major versions that causes a conflict.
230         halToAdd.forEachInstance([this, &halToAdd](const auto& manifestInstanceToAdd) {
231             removeHals(halToAdd.name, manifestInstanceToAdd.version().majorVer);
232             return true;  // continue
233         });
234     }
235 
236     if (!shouldAdd(halToAdd, error)) {
237         return false;
238     }
239 
240     CHECK(addInternal(std::move(halToAdd)) != nullptr);
241     return true;
242 }
243 
addAllHals(HalManifest * other,std::string * error)244 bool HalManifest::addAllHals(HalManifest* other, std::string* error) {
245     for (auto& pair : other->mHals) {
246         if (!add(std::move(pair.second), error)) {
247             if (error) {
248                 error->insert(0, "HAL \"" + pair.first + "\" has a conflict: ");
249             }
250             return false;
251         }
252     }
253     other->mHals.clear();
254     return true;
255 }
256 
shouldAddXmlFile(const ManifestXmlFile & xmlFile) const257 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const {
258     auto existingXmlFiles = getXmlFiles(xmlFile.name());
259     for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) {
260         if (xmlFile.version() == it->second.version()) {
261             return false;
262         }
263     }
264     return true;
265 }
266 
getHalNames() const267 std::set<std::string> HalManifest::getHalNames() const {
268     std::set<std::string> names{};
269     for (const auto &hal : mHals) {
270         names.insert(hal.first);
271     }
272     return names;
273 }
274 
getHalNamesAndVersions() const275 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
276     std::set<std::string> names{};
277     forEachInstance([&names](const ManifestInstance& e) {
278         names.insert(e.nameWithVersion());
279         return true;
280     });
281     return names;
282 }
283 
getHidlTransport(const std::string & package,const Version & v,const std::string & interfaceName,const std::string & instanceName) const284 Transport HalManifest::getHidlTransport(const std::string& package, const Version& v,
285                                         const std::string& interfaceName,
286                                         const std::string& instanceName) const {
287     Transport transport{Transport::EMPTY};
288     forEachInstanceOfInterface(HalFormat::HIDL, ExclusiveTo::EMPTY, package, v, interfaceName,
289                                [&](const auto& e) {
290                                    if (e.instance() == instanceName) {
291                                        transport = e.transport();
292                                    }
293                                    return transport == Transport::EMPTY;  // if not found, continue
294                                });
295     if (transport == Transport::EMPTY) {
296         LOG(DEBUG) << "HalManifest::getHidlTransport(" << mType << "): Cannot find "
297                    << toFQNameString(package, v, interfaceName, instanceName);
298     }
299     return transport;
300 }
301 
forEachInstanceOfVersion(HalFormat format,ExclusiveTo exclusiveTo,const std::string & package,const Version & expectVersion,const std::function<bool (const ManifestInstance &)> & func) const302 bool HalManifest::forEachInstanceOfVersion(
303     HalFormat format, ExclusiveTo exclusiveTo, const std::string& package,
304     const Version& expectVersion, const std::function<bool(const ManifestInstance&)>& func) const {
305     for (const ManifestHal* hal : getHals(package)) {
306         bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
307             if (manifestInstance.format() == format &&
308                 manifestInstance.version().minorAtLeast(expectVersion) &&
309                 manifestInstance.exclusiveTo() == exclusiveTo) {
310                 return func(manifestInstance);
311             }
312             return true;
313         });
314         if (!cont) return false;
315     }
316     return true;
317 }
318 
forEachNativeInstance(const std::string & package,const std::function<bool (const ManifestInstance &)> & func) const319 bool HalManifest::forEachNativeInstance(
320     const std::string& package, const std::function<bool(const ManifestInstance&)>& func) const {
321     for (const ManifestHal* hal : getHals(package)) {
322         bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
323             if (manifestInstance.format() == HalFormat::NATIVE) {
324                 return func(manifestInstance);
325             }
326             return true;
327         });
328         if (!cont) return false;
329     }
330     return true;
331 }
332 
333 // indent = 2, {"foo"} => "foo"
334 // indent = 2, {"foo", "bar"} => "\n  foo\n  bar";
335 template <typename Container>
multilineIndent(std::ostream & os,size_t indent,const Container & lines)336 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) {
337     if (lines.size() == 1) {
338         os << *lines.begin();
339         return;
340     }
341     for (const auto& line : lines) {
342         os << "\n";
343         for (size_t i = 0; i < indent; ++i) os << " ";
344         os << line;
345     }
346 }
347 
348 // For each hal in mat, there must be a hal in manifest that supports this.
checkIncompatibleHals(const CompatibilityMatrix & mat) const349 std::vector<std::string> HalManifest::checkIncompatibleHals(const CompatibilityMatrix& mat) const {
350     std::vector<std::string> ret;
351     for (const MatrixHal &matrixHal : mat.getHals()) {
352         if (matrixHal.optional) {
353             continue;
354         }
355 
356         std::set<FqInstance> manifestInstances;
357         std::set<std::string> manifestInstanceDesc;
358         std::set<Version> versions;
359         for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
360             manifestHal->forEachInstance([&](const auto& manifestInstance) {
361                 manifestInstances.insert(manifestInstance.getFqInstance());
362                 manifestInstanceDesc.insert(manifestInstance.descriptionWithoutPackage());
363                 return true;
364             });
365             manifestHal->appendAllVersions(&versions);
366         }
367 
368         if (!matrixHal.isCompatible(manifestInstances, versions)) {
369             std::ostringstream oss;
370             oss << matrixHal.name << ":\n    required: ";
371             multilineIndent(oss, 8, android::vintf::expandInstances(matrixHal));
372             oss << "\n    provided: ";
373             if (manifestInstances.empty()) {
374                 multilineIndent(oss, 8, versions);
375             } else {
376                 multilineIndent(oss, 8, manifestInstanceDesc);
377             }
378 
379             ret.insert(ret.end(), oss.str());
380         }
381     }
382     return ret;
383 }
384 
checkUnusedHals(const CompatibilityMatrix & mat,const std::vector<HidlInterfaceMetadata> & hidlMetadata) const385 std::set<std::string> HalManifest::checkUnusedHals(
386     const CompatibilityMatrix& mat, const std::vector<HidlInterfaceMetadata>& hidlMetadata) const {
387     std::multimap<std::string, std::string> childrenMap;
388     for (const auto& child : hidlMetadata) {
389         for (const auto& parent : child.inherited) {
390             childrenMap.emplace(parent, child.name);
391         }
392     }
393 
394     std::set<std::string> ret;
395 
396     forEachInstance([&ret, &mat, &childrenMap](const auto& manifestInstance) {
397         if (mat.matchInstance(manifestInstance.format(), manifestInstance.exclusiveTo(),
398                               manifestInstance.package(), manifestInstance.version(),
399                               manifestInstance.interface(), manifestInstance.instance())) {
400             // manifestInstance exactly matches an instance in |mat|.
401             return true;
402         }
403         // For HIDL instances, If [email protected] inherits from [email protected], manifest may contain both, but
404         // matrix may contain only 2.0 if 1.0 is considered deprecated. Hence, if manifestInstance
405         // is 1.0, check all its children in the matrix too.
406         // If there is at least one match, do not consider it unused.
407         if (manifestInstance.format() == HalFormat::HIDL) {
408             auto range =
409                 childrenMap.equal_range(manifestInstance.getFqInstance().getFqNameString());
410             for (auto it = range.first; it != range.second; ++it) {
411                 details::FQName fqName;
412                 CHECK(fqName.setTo(it->second));
413                 if (mat.matchInstance(manifestInstance.format(), manifestInstance.exclusiveTo(),
414                                       fqName.package(), fqName.getVersion(), fqName.name(),
415                                       manifestInstance.instance())) {
416                     return true;
417                 }
418             }
419         }
420 
421         // If no match is found, consider it unused.
422         ret.insert(manifestInstance.description());
423         return true;
424     });
425 
426     return ret;
427 }
428 
checkVendorNdkCompatibility(const VendorNdk & matVendorNdk,const std::vector<VendorNdk> & manifestVendorNdk,std::string * error)429 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
430                                         const std::vector<VendorNdk>& manifestVendorNdk,
431                                         std::string* error) {
432     // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
433     // tag. Ignore the check for these devices.
434     // VNDK is no longer a dependency for vendor version 35 and beyond. On these images,
435     // <vendor-ndk> is also empty.
436     if (matVendorNdk.version().empty()) {
437         return true;
438     }
439     for (const auto& vndk : manifestVendorNdk) {
440         if (vndk.version() != matVendorNdk.version()) {
441             continue;
442         }
443         // version matches, check libraries
444         std::vector<std::string> diff;
445         std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
446                             vndk.libraries().begin(), vndk.libraries().end(),
447                             std::inserter(diff, diff.begin()));
448         if (!diff.empty()) {
449             if (error != nullptr) {
450                 *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
451                          ". These libs are not in framework manifest:";
452                 for (const auto& name : diff) {
453                     *error += " " + name;
454                 }
455             }
456             return false;
457         }
458         return true;
459     }
460 
461     // no match is found.
462     if (error != nullptr) {
463         *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
464                  "Supported versions in framework manifest are: [";
465         for (const auto& vndk : manifestVendorNdk) {
466             *error += " " + vndk.version();
467         }
468         *error += "]";
469     }
470     return false;
471 }
472 
checkSystemSdkCompatibility(const SystemSdk & matSystemSdk,const SystemSdk & manifestSystemSdk,std::string * error)473 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk,
474                                         const SystemSdk& manifestSystemSdk, std::string* error) {
475     SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk);
476     if (!notSupported.empty()) {
477         if (error) {
478             *error =
479                 "The following System SDK versions are required by device "
480                 "compatibility matrix but not supported by the framework manifest: [" +
481                 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" +
482                 base::Join(manifestSystemSdk.versions(), ", ") + "].";
483         }
484         return false;
485     }
486     return true;
487 }
488 
checkCompatibility(const CompatibilityMatrix & mat,std::string * error,CheckFlags::Type flags) const489 bool HalManifest::checkCompatibility(const CompatibilityMatrix& mat, std::string* error,
490                                      CheckFlags::Type flags) const {
491     if (mType == mat.mType) {
492         if (error != nullptr) {
493             *error = "Wrong type; checking " + to_string(mType) + " manifest against "
494                     + to_string(mat.mType) + " compatibility matrix";
495         }
496         return false;
497     }
498     auto incompatibleHals = checkIncompatibleHals(mat);
499     if (!incompatibleHals.empty()) {
500         if (error != nullptr) {
501             *error = "HALs incompatible.";
502             if (mat.level() != Level::UNSPECIFIED)
503                 *error += " Matrix level = " + to_string(mat.level()) + ".";
504             if (level() != Level::UNSPECIFIED)
505                 *error += " Manifest level = " + to_string(level()) + ".";
506             *error += " The following requirements are not met:\n";
507             for (const auto& e : incompatibleHals) {
508                 *error += e + "\n";
509             }
510         }
511         return false;
512     }
513     if (mType == SchemaType::FRAMEWORK) {
514         if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
515             return false;
516         }
517 
518         if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) {
519             return false;
520         }
521     } else if (mType == SchemaType::DEVICE) {
522         bool sepolicyMatch = false;
523         for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
524             if (range.supportedBy(device.mSepolicyVersion)) {
525                 sepolicyMatch = true;
526                 break;
527             }
528         }
529         if (!sepolicyMatch) {
530             if (error != nullptr) {
531                 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
532                         + " doesn't satisify the requirements.";
533             }
534             return false;
535         }
536 
537         // Not using inferredKernelLevel() to preserve the legacy behavior if <kernel> does not have
538         // level attribute.
539         // Note that shouldCheckKernelCompatibility() only returns true on host, because the
540         // on-device HalManifest does not have kernel version set. On the device, kernel information
541         // is retrieved from RuntimeInfo.
542         Level kernelTagLevel = kernel()->level();
543         if (flags.isKernelEnabled() && shouldCheckKernelCompatibility() &&
544             kernel()
545                 ->getMatchedKernelRequirements(mat.framework.mKernels, kernelTagLevel, error)
546                 .empty()) {
547             return false;
548         }
549     }
550 
551     return true;
552 }
553 
shouldCheckKernelCompatibility() const554 bool HalManifest::shouldCheckKernelCompatibility() const {
555     return kernel().has_value() && kernel()->version() != KernelVersion{};
556 }
557 
generateCompatibleMatrix(bool optional) const558 CompatibilityMatrix HalManifest::generateCompatibleMatrix(bool optional) const {
559     CompatibilityMatrix matrix;
560 
561     std::set<std::tuple<HalFormat, std::string, Version, std::string, std::string>> instances;
562 
563     forEachInstance([&matrix, &instances, optional](const ManifestInstance& e) {
564         auto&& [it, added] =
565             instances.emplace(e.format(), e.package(), e.version(), e.interface(), e.instance());
566         if (!added) {
567             return true;
568         }
569 
570         matrix.add(MatrixHal{
571             .format = e.format(),
572             .name = e.package(),
573             .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}},
574             .optional = optional,
575             .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}});
576         return true;
577     });
578     if (mType == SchemaType::FRAMEWORK) {
579         matrix.mType = SchemaType::DEVICE;
580         // VNDK does not need to be added for compatibility
581     } else if (mType == SchemaType::DEVICE) {
582         matrix.mType = SchemaType::FRAMEWORK;
583         matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
584                 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
585     }
586 
587     return matrix;
588 }
589 
fetchAllInformation(const FileSystem * fileSystem,const std::string & path,std::string * error)590 status_t HalManifest::fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
591                                           std::string* error) {
592     return details::fetchAllInformation(fileSystem, path, this, error);
593 }
594 
type() const595 SchemaType HalManifest::type() const {
596     return mType;
597 }
598 
setType(SchemaType type)599 void HalManifest::setType(SchemaType type) {
600     mType = type;
601 }
602 
level() const603 Level HalManifest::level() const {
604     return mLevel;
605 }
606 
sepolicyVersion() const607 const SepolicyVersion& HalManifest::sepolicyVersion() const {
608     CHECK(mType == SchemaType::DEVICE);
609     return device.mSepolicyVersion;
610 }
611 
vendorNdks() const612 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
613     CHECK(mType == SchemaType::FRAMEWORK);
614     return framework.mVendorNdks;
615 }
616 
getXmlFilePath(const std::string & xmlFileName,const Version & version) const617 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
618                                         const Version& version) const {
619     using std::literals::string_literals::operator""s;
620     auto range = getXmlFiles(xmlFileName);
621     for (auto it = range.first; it != range.second; ++it) {
622         const ManifestXmlFile& manifestXmlFile = it->second;
623         if (manifestXmlFile.version() == version) {
624             if (!manifestXmlFile.overriddenPath().empty()) {
625                 return manifestXmlFile.overriddenPath();
626             }
627             return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
628                    xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
629                    std::to_string(version.minorVer) + ".xml";
630         }
631     }
632     return "";
633 }
634 
operator ==(const HalManifest & lft,const HalManifest & rgt)635 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
636     // ignore fileName().
637     return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
638            lft.mXmlFiles == rgt.mXmlFiles &&
639            (lft.mType != SchemaType::DEVICE ||
640             (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion &&
641              lft.device.mKernel == rgt.device.mKernel)) &&
642            (lft.mType != SchemaType::FRAMEWORK ||
643             (
644 #pragma clang diagnostic push
645 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
646                 lft.framework.mVndks == rgt.framework.mVndks &&
647 #pragma clang diagnostic pop
648                 lft.framework.mVendorNdks == rgt.framework.mVendorNdks &&
649                 lft.framework.mSystemSdk == rgt.framework.mSystemSdk));
650 }
651 
652 // Alternative to forEachInstance if you just need a set of instance names instead.
getInstances(HalFormat format,ExclusiveTo exclusiveTo,const std::string & package,const Version & version,const std::string & interfaceName) const653 std::set<std::string> HalManifest::getInstances(HalFormat format, ExclusiveTo exclusiveTo,
654                                                 const std::string& package, const Version& version,
655                                                 const std::string& interfaceName) const {
656     std::set<std::string> ret;
657     (void)forEachInstanceOfInterface(format, exclusiveTo, package, version, interfaceName,
658                                      [&ret](const auto& e) {
659                                          ret.insert(e.instance());
660                                          return true;
661                                      });
662     return ret;
663 }
664 
665 // Return whether instance is in getInstances(...).
hasInstance(HalFormat format,ExclusiveTo exclusiveTo,const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const666 bool HalManifest::hasInstance(HalFormat format, ExclusiveTo exclusiveTo, const std::string& package,
667                               const Version& version, const std::string& interfaceName,
668                               const std::string& instance) const {
669     bool found = false;
670     (void)forEachInstanceOfInterface(format, exclusiveTo, package, version, interfaceName,
671                                      [&found, &instance](const auto& e) {
672                                          found |= (instance == e.instance());
673                                          return !found;  // if not found, continue
674                                      });
675     return found;
676 }
getHidlInstances(const std::string & package,const Version & version,const std::string & interfaceName) const677 std::set<std::string> HalManifest::getHidlInstances(const std::string& package,
678                                                     const Version& version,
679                                                     const std::string& interfaceName) const {
680     return getInstances(HalFormat::HIDL, ExclusiveTo::EMPTY, package, version, interfaceName);
681 }
682 
getAidlInstances(const std::string & package,const std::string & interfaceName) const683 std::set<std::string> HalManifest::getAidlInstances(const std::string& package,
684                                                     const std::string& interfaceName) const {
685     // Only get the instances available on the host device with ExclusiveTo::EMPTY
686     return getAidlInstances(package, 0, interfaceName);
687 }
688 
getAidlInstances(const std::string & package,size_t version,const std::string & interfaceName) const689 std::set<std::string> HalManifest::getAidlInstances(const std::string& package, size_t version,
690                                                     const std::string& interfaceName) const {
691     // Only get the instances available on the host device with ExclusiveTo::EMPTY
692     return getInstances(HalFormat::AIDL, ExclusiveTo::EMPTY, package,
693                         {details::kFakeAidlMajorVersion, version}, interfaceName);
694 }
695 
getNativeInstances(const std::string & package) const696 std::set<std::string> HalManifest::getNativeInstances(const std::string& package) const {
697     std::set<std::string> instances;
698     forEachNativeInstance(package, [&](const auto& inst) {
699         instances.insert(inst.instance());
700         return true;
701     });
702     return instances;
703 }
704 
hasHidlInstance(const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const705 bool HalManifest::hasHidlInstance(const std::string& package, const Version& version,
706                                   const std::string& interfaceName,
707                                   const std::string& instance) const {
708     return hasInstance(HalFormat::HIDL, ExclusiveTo::EMPTY, package, version, interfaceName,
709                        instance);
710 }
711 
hasAidlInstance(const std::string & package,const std::string & interface,const std::string & instance) const712 bool HalManifest::hasAidlInstance(const std::string& package, const std::string& interface,
713                                   const std::string& instance) const {
714     return hasAidlInstance(package, 0, interface, instance);
715 }
716 
hasAidlInstance(const std::string & package,size_t version,const std::string & interface,const std::string & instance) const717 bool HalManifest::hasAidlInstance(const std::string& package, size_t version,
718                                   const std::string& interface, const std::string& instance) const {
719     return hasInstance(HalFormat::AIDL, ExclusiveTo::EMPTY, package,
720                        {details::kFakeAidlMajorVersion, version}, interface, instance);
721 }
722 
hasNativeInstance(const std::string & package,const std::string & instance) const723 bool HalManifest::hasNativeInstance(const std::string& package, const std::string& instance) const {
724     bool found = false;
725     forEachNativeInstance(package, [&](const auto& inst) {
726         found |= inst.instance() == instance;
727         return !found;  // continue if not found
728     });
729     return found;
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