• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "libvintf"
18 #include <android-base/logging.h>
19 
20 #include "HalManifest.h"
21 
22 #include <dirent.h>
23 
24 #include <algorithm>
25 #include <mutex>
26 #include <set>
27 
28 #include <android-base/strings.h>
29 
30 #include "CompatibilityMatrix.h"
31 #include "constants-private.h"
32 #include "constants.h"
33 #include "parse_string.h"
34 #include "parse_xml.h"
35 #include "utils.h"
36 
37 namespace android {
38 namespace vintf {
39 
40 using details::Instances;
41 using details::InstancesOfVersion;
42 using details::mergeField;
43 
44 // Check <version> tag for all <hal> with the same name.
shouldAdd(const ManifestHal & hal,std::string * error) const45 bool HalManifest::shouldAdd(const ManifestHal& hal, std::string* error) const {
46     if (!hal.isValid(error)) {
47         if (error) {
48             error->insert(0, "HAL '" + hal.name + "' is not valid: ");
49             if (!hal.fileName().empty()) {
50                 error->insert(0, "For file " + hal.fileName() + ": ");
51             }
52         }
53         return false;
54     }
55     if (hal.isOverride()) {
56         return true;
57     }
58     if (!addingConflictingMajorVersion(hal, error)) {
59         return false;
60     }
61     return addingConflictingFqInstance(hal, error);
62 }
63 
addingConflictingMajorVersion(const ManifestHal & hal,std::string * error) const64 bool HalManifest::addingConflictingMajorVersion(const ManifestHal& hal, std::string* error) const {
65     // Skip checking for AIDL HALs because they all contain kFakeAidlMajorVersion.
66     if (hal.format == HalFormat::AIDL) {
67         return true;
68     }
69 
70     auto existingHals = mHals.equal_range(hal.name);
71     std::map<size_t, std::tuple<const ManifestHal*, Version>> existing;
72     for (auto it = existingHals.first; it != existingHals.second; ++it) {
73         const ManifestHal& existingHal = it->second;
74         for (const auto& v : existingHal.versions) {
75             // Assume integrity on existingHals, so no check on emplace().second
76             existing.emplace(v.majorVer, std::make_tuple(&existingHal, v));
77         }
78     }
79     bool success = true;
80     for (const auto& v : hal.versions) {
81         auto&& [existingIt, inserted] = existing.emplace(v.majorVer, std::make_tuple(&hal, v));
82         if (inserted) {
83             continue;
84         }
85         success = false;
86         if (error) {
87             auto&& [existingHal, existingVersion] = existingIt->second;
88             *error = "Conflicting major version: " + to_string(existingVersion);
89             if (!existingHal->fileName().empty()) {
90                 *error += " (from " + existingHal->fileName() + ")";
91             }
92             *error += " vs. " + to_string(v);
93             if (!hal.fileName().empty()) {
94                 *error += " (from " + hal.fileName() + ")";
95             }
96             *error +=
97                 ". Check whether or not multiple modules providing the same HAL are installed.";
98         }
99     }
100 
101     return success;
102 }
103 
addingConflictingFqInstance(const ManifestHal & halToAdd,std::string * error) const104 bool HalManifest::addingConflictingFqInstance(const ManifestHal& halToAdd,
105                                               std::string* error) const {
106     if (mSourceMetaVersion < kMetaVersionNoHalInterfaceInstance) {
107         return true;
108     }
109 
110     auto existingHals = mHals.equal_range(halToAdd.name);
111 
112     // Key: FqInstance with minor version 0
113     // Value: original HAL and FqInstance
114     std::map<FqInstance, std::tuple<const ManifestHal*, ManifestInstance>> existing;
115     std::map<std::string, std::tuple<const ManifestHal*, ManifestInstance>> existingAccessors;
116     for (auto it = existingHals.first; it != existingHals.second; ++it) {
117         const ManifestHal& existingHal = it->second;
118         bool success = existingHal.forEachInstance(
119             [&existingHal, &existing, &existingAccessors](const auto& manifestInstance) {
120                 auto versionZero = manifestInstance.version().withMinor(0);
121                 auto key = manifestInstance.withVersion(versionZero).getFqInstance();
122                 // Assume integrity on existingHals, so no check on emplace().second
123                 existing.emplace(key, std::make_tuple(&existingHal, manifestInstance));
124                 if (auto accessor = manifestInstance.accessor(); accessor.has_value()) {
125                     existingAccessors.emplace(accessor.value(),
126                                               std::make_tuple(&existingHal, manifestInstance));
127                 }
128                 return true;  // continue
129             });
130         if (!success) {
131             return false;
132         }
133     }
134     return halToAdd.forEachInstance([&halToAdd, &existing, &existingAccessors,
135                                      &error](const auto& manifestInstanceToAdd) {
136         auto constructErrorMessage = [&halToAdd, &manifestInstanceToAdd](
137                                          const auto& existingManifestInstance,
138                                          const auto& existingHal) {
139             std::string errorMsg = existingManifestInstance.descriptionWithoutPackage();
140             if (!existingHal->fileName().empty()) {
141                 errorMsg += " (from " + existingHal->fileName() + ")";
142             }
143             errorMsg += " vs. " + manifestInstanceToAdd.descriptionWithoutPackage();
144             if (!halToAdd.fileName().empty()) {
145                 errorMsg += " (from " + halToAdd.fileName() + ")";
146             }
147             return errorMsg;
148         };
149 
150         auto versionZero = manifestInstanceToAdd.version().withMinor(0);
151         auto key = manifestInstanceToAdd.withVersion(versionZero).getFqInstance();
152 
153         // Check duplicate FqInstance.
154         auto&& [existingIt, inserted] =
155             existing.emplace(key, std::make_tuple(&halToAdd, manifestInstanceToAdd));
156         if (!inserted) {
157             if (error) {
158                 auto&& [existingHal, existingManifestInstance] = existingIt->second;
159                 *error = "Conflicting FqInstance: ";
160                 *error += constructErrorMessage(existingManifestInstance, existingHal);
161                 *error +=
162                     ". Check whether or not multiple modules providing the same HAL are installed.";
163             }
164             return false;  // break and let addingConflictingFqInstance return false
165         }
166 
167         // Check duplicate accessor.
168         auto accessor = manifestInstanceToAdd.accessor();
169         if (!accessor.has_value()) {
170             return true;
171         }
172         auto&& [existingAccessorIt, insertedAccessor] = existingAccessors.emplace(
173             accessor.value(), std::make_tuple(&halToAdd, manifestInstanceToAdd));
174         if (insertedAccessor) {
175             return true;
176         }
177         if (error) {
178             auto&& [existingHal, existingManifestInstance] = existingAccessorIt->second;
179             *error = "Conflicting Accessor: ";
180             *error += constructErrorMessage(existingManifestInstance, existingHal);
181             *error +=
182                 ". Check whether or not multiple modules providing the same accessor are "
183                 "installed.";
184         }
185         return false;  // break and let addingConflictingFqInstance return false
186     });
187 }
188 
189 // Remove elements from "list" if p(element) returns true.
190 template <typename List, typename Predicate>
removeIf(List & list,Predicate predicate)191 static void removeIf(List& list, Predicate predicate) {
192     for (auto it = list.begin(); it != list.end();) {
193         if (predicate(*it)) {
194             it = list.erase(it);
195         } else {
196             ++it;
197         }
198     }
199 }
200 
removeHals(const std::string & name,size_t majorVer)201 void HalManifest::removeHals(const std::string& name, size_t majorVer) {
202     removeIf(mHals, [&name, majorVer](auto& existingHalPair) {
203         auto& existingHal = existingHalPair.second;
204         if (existingHal.name != name) {
205             return false;
206         }
207         auto& existingVersions = existingHal.versions;
208         removeIf(existingVersions, [majorVer](const auto& existingVersion) {
209             return existingVersion.majorVer == majorVer;
210         });
211         auto& existingManifestInstances = existingHal.mManifestInstances;
212         removeIf(existingManifestInstances, [majorVer](const auto& existingManifestInstance) {
213             return existingManifestInstance.version().majorVer == majorVer;
214         });
215         return existingVersions.empty() && existingManifestInstances.empty();
216     });
217 }
218 
add(ManifestHal && halToAdd,std::string * error)219 bool HalManifest::add(ManifestHal&& halToAdd, std::string* error) {
220     if (halToAdd.isOverride()) {
221         if (halToAdd.isDisabledHal()) {
222             // Special syntax when there are no instances at all. Remove all existing HALs
223             // with the given name.
224             mHals.erase(halToAdd.name);
225         }
226         // If there are <version> tags, remove all existing major versions that causes a conflict.
227         for (const Version& versionToAdd : halToAdd.versions) {
228             removeHals(halToAdd.name, versionToAdd.majorVer);
229         }
230         // If there are <fqname> tags, remove all existing major versions that causes a conflict.
231         halToAdd.forEachInstance([this, &halToAdd](const auto& manifestInstanceToAdd) {
232             removeHals(halToAdd.name, manifestInstanceToAdd.version().majorVer);
233             return true;  // continue
234         });
235     }
236 
237     if (!shouldAdd(halToAdd, error)) {
238         return false;
239     }
240 
241     CHECK(addInternal(std::move(halToAdd)) != nullptr);
242     return true;
243 }
244 
addAllHals(HalManifest * other,std::string * error)245 bool HalManifest::addAllHals(HalManifest* other, std::string* error) {
246     for (auto& pair : other->mHals) {
247         if (!add(std::move(pair.second), error)) {
248             if (error) {
249                 error->insert(0, "HAL \"" + pair.first + "\" has a conflict: ");
250             }
251             return false;
252         }
253     }
254     other->mHals.clear();
255     return true;
256 }
257 
shouldAddXmlFile(const ManifestXmlFile & xmlFile) const258 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const {
259     auto existingXmlFiles = getXmlFiles(xmlFile.name());
260     for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) {
261         if (xmlFile.version() == it->second.version()) {
262             return false;
263         }
264     }
265     return true;
266 }
267 
getHalNames() const268 std::set<std::string> HalManifest::getHalNames() const {
269     std::set<std::string> names{};
270     for (const auto &hal : mHals) {
271         names.insert(hal.first);
272     }
273     return names;
274 }
275 
getHalNamesAndVersions() const276 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
277     std::set<std::string> names{};
278     forEachInstance([&names](const ManifestInstance& e) {
279         names.insert(e.nameWithVersion());
280         return true;
281     });
282     return names;
283 }
284 
getHidlTransport(const std::string & package,const Version & v,const std::string & interfaceName,const std::string & instanceName) const285 Transport HalManifest::getHidlTransport(const std::string& package, const Version& v,
286                                         const std::string& interfaceName,
287                                         const std::string& instanceName) const {
288     Transport transport{Transport::EMPTY};
289     forEachInstanceOfInterface(HalFormat::HIDL, ExclusiveTo::EMPTY, package, v, interfaceName,
290                                [&](const auto& e) {
291                                    if (e.instance() == instanceName) {
292                                        transport = e.transport();
293                                    }
294                                    return transport == Transport::EMPTY;  // if not found, continue
295                                });
296     if (transport == Transport::EMPTY) {
297         LOG(DEBUG) << "HalManifest::getHidlTransport(" << mType << "): Cannot find "
298                    << toFQNameString(package, v, interfaceName, instanceName);
299     }
300     return transport;
301 }
302 
forEachInstanceOfVersion(HalFormat format,ExclusiveTo exclusiveTo,const std::string & package,const Version & expectVersion,const std::function<bool (const ManifestInstance &)> & func) const303 bool HalManifest::forEachInstanceOfVersion(
304     HalFormat format, ExclusiveTo exclusiveTo, const std::string& package,
305     const Version& expectVersion, const std::function<bool(const ManifestInstance&)>& func) const {
306     for (const ManifestHal* hal : getHals(package)) {
307         bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
308             if (manifestInstance.format() == format &&
309                 manifestInstance.version().minorAtLeast(expectVersion) &&
310                 manifestInstance.exclusiveTo() == exclusiveTo) {
311                 return func(manifestInstance);
312             }
313             return true;
314         });
315         if (!cont) return false;
316     }
317     return true;
318 }
319 
forEachNativeInstance(const std::string & package,const std::function<bool (const ManifestInstance &)> & func) const320 bool HalManifest::forEachNativeInstance(
321     const std::string& package, const std::function<bool(const ManifestInstance&)>& func) const {
322     for (const ManifestHal* hal : getHals(package)) {
323         bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
324             if (manifestInstance.format() == HalFormat::NATIVE) {
325                 return func(manifestInstance);
326             }
327             return true;
328         });
329         if (!cont) return false;
330     }
331     return true;
332 }
333 
334 // indent = 2, {"foo"} => "foo"
335 // indent = 2, {"foo", "bar"} => "\n  foo\n  bar";
336 template <typename Container>
multilineIndent(std::ostream & os,size_t indent,const Container & lines)337 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) {
338     if (lines.size() == 1) {
339         os << *lines.begin();
340         return;
341     }
342     for (const auto& line : lines) {
343         os << "\n";
344         for (size_t i = 0; i < indent; ++i) os << " ";
345         os << line;
346     }
347 }
348 
checkUnusedHals(const CompatibilityMatrix & mat,const std::vector<HidlInterfaceMetadata> & hidlMetadata) const349 std::set<std::string> HalManifest::checkUnusedHals(
350     const CompatibilityMatrix& mat, const std::vector<HidlInterfaceMetadata>& hidlMetadata) const {
351     std::multimap<std::string, std::string> childrenMap;
352     for (const auto& child : hidlMetadata) {
353         for (const auto& parent : child.inherited) {
354             childrenMap.emplace(parent, child.name);
355         }
356     }
357 
358     std::set<std::string> ret;
359 
360     forEachInstance([&ret, &mat, &childrenMap](const auto& manifestInstance) {
361         if (mat.matchInstance(manifestInstance.format(), manifestInstance.exclusiveTo(),
362                               manifestInstance.package(), manifestInstance.version(),
363                               manifestInstance.interface(), manifestInstance.instance())) {
364             // manifestInstance exactly matches an instance in |mat|.
365             return true;
366         }
367         // For HIDL instances, If foo@2.0 inherits from foo@1.0, manifest may contain both, but
368         // matrix may contain only 2.0 if 1.0 is considered deprecated. Hence, if manifestInstance
369         // is 1.0, check all its children in the matrix too.
370         // If there is at least one match, do not consider it unused.
371         if (manifestInstance.format() == HalFormat::HIDL) {
372             auto range =
373                 childrenMap.equal_range(manifestInstance.getFqInstance().getFqNameString());
374             for (auto it = range.first; it != range.second; ++it) {
375                 details::FQName fqName;
376                 CHECK(fqName.setTo(it->second));
377                 if (mat.matchInstance(manifestInstance.format(), manifestInstance.exclusiveTo(),
378                                       fqName.package(), fqName.getVersion(), fqName.name(),
379                                       manifestInstance.instance())) {
380                     return true;
381                 }
382             }
383         }
384 
385         // If no match is found, consider it unused.
386         ret.insert(manifestInstance.description());
387         return true;
388     });
389 
390     return ret;
391 }
392 
checkVendorNdkCompatibility(const VendorNdk & matVendorNdk,const std::vector<VendorNdk> & manifestVendorNdk,std::string * error)393 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
394                                         const std::vector<VendorNdk>& manifestVendorNdk,
395                                         std::string* error) {
396     // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
397     // tag. Ignore the check for these devices.
398     // VNDK is no longer a dependency for vendor version 35 and beyond. On these images,
399     // <vendor-ndk> is also empty.
400     if (matVendorNdk.version().empty()) {
401         return true;
402     }
403     for (const auto& vndk : manifestVendorNdk) {
404         if (vndk.version() != matVendorNdk.version()) {
405             continue;
406         }
407         // version matches, check libraries
408         std::vector<std::string> diff;
409         std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
410                             vndk.libraries().begin(), vndk.libraries().end(),
411                             std::inserter(diff, diff.begin()));
412         if (!diff.empty()) {
413             if (error != nullptr) {
414                 *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
415                          ". These libs are not in framework manifest:";
416                 for (const auto& name : diff) {
417                     *error += " " + name;
418                 }
419             }
420             return false;
421         }
422         return true;
423     }
424 
425     // no match is found.
426     if (error != nullptr) {
427         *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
428                  "Supported versions in framework manifest are: [";
429         for (const auto& vndk : manifestVendorNdk) {
430             *error += " " + vndk.version();
431         }
432         *error += "]";
433     }
434     return false;
435 }
436 
checkSystemSdkCompatibility(const SystemSdk & matSystemSdk,const SystemSdk & manifestSystemSdk,std::string * error)437 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk,
438                                         const SystemSdk& manifestSystemSdk, std::string* error) {
439     SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk);
440     if (!notSupported.empty()) {
441         if (error) {
442             *error =
443                 "The following System SDK versions are required by device "
444                 "compatibility matrix but not supported by the framework manifest: [" +
445                 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" +
446                 base::Join(manifestSystemSdk.versions(), ", ") + "].";
447         }
448         return false;
449     }
450     return true;
451 }
452 
checkCompatibility(const CompatibilityMatrix & mat,std::string * error,CheckFlags::Type flags) const453 bool HalManifest::checkCompatibility(const CompatibilityMatrix& mat, std::string* error,
454                                      CheckFlags::Type flags) const {
455     if (mType == mat.mType) {
456         if (error != nullptr) {
457             *error = "Wrong type; checking " + to_string(mType) + " manifest against "
458                     + to_string(mat.mType) + " compatibility matrix";
459         }
460         return false;
461     }
462     if (mType == SchemaType::FRAMEWORK) {
463         if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
464             return false;
465         }
466 
467         if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) {
468             return false;
469         }
470     } else if (mType == SchemaType::DEVICE) {
471         bool sepolicyMatch = false;
472         for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
473             if (range.supportedBy(device.mSepolicyVersion)) {
474                 sepolicyMatch = true;
475                 break;
476             }
477         }
478         if (!sepolicyMatch) {
479             if (error != nullptr) {
480                 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
481                         + " doesn't satisify the requirements.";
482             }
483             return false;
484         }
485 
486         // Not using inferredKernelLevel() to preserve the legacy behavior if <kernel> does not have
487         // level attribute.
488         // Note that shouldCheckKernelCompatibility() only returns true on host, because the
489         // on-device HalManifest does not have kernel version set. On the device, kernel information
490         // is retrieved from RuntimeInfo.
491         Level kernelTagLevel = kernel()->level();
492         if (flags.isKernelEnabled() && shouldCheckKernelCompatibility() &&
493             kernel()
494                 ->getMatchedKernelRequirements(mat.framework.mKernels, kernelTagLevel, error)
495                 .empty()) {
496             return false;
497         }
498     }
499 
500     return true;
501 }
502 
shouldCheckKernelCompatibility() const503 bool HalManifest::shouldCheckKernelCompatibility() const {
504     return kernel().has_value() && kernel()->version() != KernelVersion{};
505 }
506 
generateCompatibleMatrix() const507 CompatibilityMatrix HalManifest::generateCompatibleMatrix() const {
508     CompatibilityMatrix matrix;
509 
510     std::set<std::tuple<HalFormat, std::string, Version, std::string, std::string>> instances;
511 
512     forEachInstance([&matrix, &instances](const ManifestInstance& e) {
513         auto&& [it, added] =
514             instances.emplace(e.format(), e.package(), e.version(), e.interface(), e.instance());
515         if (!added) {
516             return true;
517         }
518 
519         matrix.add(MatrixHal{
520             .format = e.format(),
521             .name = e.package(),
522             .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}},
523             .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}});
524         return true;
525     });
526     if (mType == SchemaType::FRAMEWORK) {
527         matrix.mType = SchemaType::DEVICE;
528         // VNDK does not need to be added for compatibility
529     } else if (mType == SchemaType::DEVICE) {
530         matrix.mType = SchemaType::FRAMEWORK;
531         matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
532                 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
533     }
534 
535     return matrix;
536 }
537 
fetchAllInformation(const FileSystem * fileSystem,const std::string & path,std::string * error)538 status_t HalManifest::fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
539                                           std::string* error) {
540     return details::fetchAllInformation(fileSystem, path, this, error);
541 }
542 
type() const543 SchemaType HalManifest::type() const {
544     return mType;
545 }
546 
setType(SchemaType type)547 void HalManifest::setType(SchemaType type) {
548     mType = type;
549 }
550 
level() const551 Level HalManifest::level() const {
552     return mLevel;
553 }
554 
sepolicyVersion() const555 const SepolicyVersion& HalManifest::sepolicyVersion() const {
556     CHECK(mType == SchemaType::DEVICE);
557     return device.mSepolicyVersion;
558 }
559 
vendorNdks() const560 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
561     CHECK(mType == SchemaType::FRAMEWORK);
562     return framework.mVendorNdks;
563 }
564 
getXmlFilePath(const std::string & xmlFileName,const Version & version) const565 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
566                                         const Version& version) const {
567     using std::literals::string_literals::operator""s;
568     auto range = getXmlFiles(xmlFileName);
569     for (auto it = range.first; it != range.second; ++it) {
570         const ManifestXmlFile& manifestXmlFile = it->second;
571         if (manifestXmlFile.version() == version) {
572             if (!manifestXmlFile.overriddenPath().empty()) {
573                 return manifestXmlFile.overriddenPath();
574             }
575             return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
576                    xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
577                    std::to_string(version.minorVer) + ".xml";
578         }
579     }
580     return "";
581 }
582 
operator ==(const HalManifest & lft,const HalManifest & rgt)583 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
584     // ignore fileName().
585     return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
586            lft.mXmlFiles == rgt.mXmlFiles &&
587            (lft.mType != SchemaType::DEVICE ||
588             (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion &&
589              lft.device.mKernel == rgt.device.mKernel)) &&
590            (lft.mType != SchemaType::FRAMEWORK ||
591             (
592 #pragma clang diagnostic push
593 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
594                 lft.framework.mVndks == rgt.framework.mVndks &&
595 #pragma clang diagnostic pop
596                 lft.framework.mVendorNdks == rgt.framework.mVendorNdks &&
597                 lft.framework.mSystemSdk == rgt.framework.mSystemSdk));
598 }
599 
600 // 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) const601 std::set<std::string> HalManifest::getInstances(HalFormat format, ExclusiveTo exclusiveTo,
602                                                 const std::string& package, const Version& version,
603                                                 const std::string& interfaceName) const {
604     std::set<std::string> ret;
605     (void)forEachInstanceOfInterface(format, exclusiveTo, package, version, interfaceName,
606                                      [&ret](const auto& e) {
607                                          ret.insert(e.instance());
608                                          return true;
609                                      });
610     return ret;
611 }
612 
613 // 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) const614 bool HalManifest::hasInstance(HalFormat format, ExclusiveTo exclusiveTo, const std::string& package,
615                               const Version& version, const std::string& interfaceName,
616                               const std::string& instance) const {
617     bool found = false;
618     (void)forEachInstanceOfInterface(format, exclusiveTo, package, version, interfaceName,
619                                      [&found, &instance](const auto& e) {
620                                          found |= (instance == e.instance());
621                                          return !found;  // if not found, continue
622                                      });
623     return found;
624 }
getHidlInstances(const std::string & package,const Version & version,const std::string & interfaceName) const625 std::set<std::string> HalManifest::getHidlInstances(const std::string& package,
626                                                     const Version& version,
627                                                     const std::string& interfaceName) const {
628     return getInstances(HalFormat::HIDL, ExclusiveTo::EMPTY, package, version, interfaceName);
629 }
630 
getAidlInstances(const std::string & package,const std::string & interfaceName) const631 std::set<std::string> HalManifest::getAidlInstances(const std::string& package,
632                                                     const std::string& interfaceName) const {
633     // Only get the instances available on the host device with ExclusiveTo::EMPTY
634     return getAidlInstances(package, 0, interfaceName);
635 }
636 
getAidlInstances(const std::string & package,size_t version,const std::string & interfaceName) const637 std::set<std::string> HalManifest::getAidlInstances(const std::string& package, size_t version,
638                                                     const std::string& interfaceName) const {
639     // Only get the instances available on the host device with ExclusiveTo::EMPTY
640     return getInstances(HalFormat::AIDL, ExclusiveTo::EMPTY, package,
641                         {details::kFakeAidlMajorVersion, version}, interfaceName);
642 }
643 
getNativeInstances(const std::string & package) const644 std::set<std::string> HalManifest::getNativeInstances(const std::string& package) const {
645     std::set<std::string> instances;
646     forEachNativeInstance(package, [&](const auto& inst) {
647         instances.insert(inst.instance());
648         return true;
649     });
650     return instances;
651 }
652 
hasHidlInstance(const std::string & package,const Version & version,const std::string & interfaceName,const std::string & instance) const653 bool HalManifest::hasHidlInstance(const std::string& package, const Version& version,
654                                   const std::string& interfaceName,
655                                   const std::string& instance) const {
656     return hasInstance(HalFormat::HIDL, ExclusiveTo::EMPTY, package, version, interfaceName,
657                        instance);
658 }
659 
hasAidlInstance(const std::string & package,const std::string & interface,const std::string & instance) const660 bool HalManifest::hasAidlInstance(const std::string& package, const std::string& interface,
661                                   const std::string& instance) const {
662     return hasAidlInstance(package, 0, interface, instance);
663 }
664 
hasAidlInstance(const std::string & package,size_t version,const std::string & interface,const std::string & instance) const665 bool HalManifest::hasAidlInstance(const std::string& package, size_t version,
666                                   const std::string& interface, const std::string& instance) const {
667     return hasInstance(HalFormat::AIDL, ExclusiveTo::EMPTY, package,
668                        {details::kFakeAidlMajorVersion, version}, interface, instance);
669 }
670 
hasNativeInstance(const std::string & package,const std::string & instance) const671 bool HalManifest::hasNativeInstance(const std::string& package, const std::string& instance) const {
672     bool found = false;
673     forEachNativeInstance(package, [&](const auto& inst) {
674         found |= inst.instance() == instance;
675         return !found;  // continue if not found
676     });
677     return found;
678 }
679 
insertInstance(const FqInstance & fqInstance,Transport transport,Arch arch,HalFormat format,std::string * error)680 bool HalManifest::insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch,
681                                  HalFormat format, std::string* error) {
682     for (ManifestHal& hal : getHals()) {
683         if (hal.name == fqInstance.getPackage() && hal.format == format &&
684             hal.transport() == transport && hal.arch() == arch) {
685             return hal.insertInstance(fqInstance, error);
686         }
687     }
688 
689     ManifestHal hal;
690     hal.name = fqInstance.getPackage();
691     hal.format = format;
692     hal.transportArch = TransportArch(transport, arch);
693     if (!hal.insertInstance(fqInstance, error)) return false;
694     return add(std::move(hal), error);
695 }
696 
empty() const697 bool HalManifest::empty() const {
698     HalManifest emptyManifest;
699     emptyManifest.setType(type());
700     return (*this) == emptyManifest;
701 }
702 
kernel() const703 const std::optional<KernelInfo>& HalManifest::kernel() const {
704     return device.mKernel;
705 }
706 
mergeKernel(std::optional<KernelInfo> * other,std::string * error)707 bool HalManifest::mergeKernel(std::optional<KernelInfo>* other, std::string* error) {
708     if (!other->has_value()) {
709         return true;
710     }
711 
712     if (device.mKernel.has_value()) {
713         if (!device.mKernel->merge(&**other, error)) {
714             return false;
715         }
716     } else {
717         device.mKernel = std::move(*other);
718     }
719 
720     *other = std::nullopt;
721     return true;
722 }
723 
addAll(HalManifest * other,std::string * error)724 bool HalManifest::addAll(HalManifest* other, std::string* error) {
725     if (type() != other->type()) {
726         if (error) {
727             *error = "Cannot add a " + to_string(other->type()) + " manifest to a " +
728                      to_string(type()) + " manifest";
729         }
730         return false;
731     }
732 
733     if (!addAllHals(other, error)) {
734         return false;
735     }
736 
737     if (!addAllXmlFiles(other, error)) {
738         return false;
739     }
740 
741     if (!mergeField(&mLevel, &other->mLevel, Level::UNSPECIFIED)) {
742         if (error) {
743             *error = "Conflicting target-level: " + to_string(level()) + " vs. " +
744                      to_string(other->level());
745         }
746         return false;
747     }
748 
749     if (type() == SchemaType::DEVICE) {
750         if (!mergeField(&device.mSepolicyVersion, &other->device.mSepolicyVersion)) {
751             if (error) {
752                 *error = "Conflicting sepolicy version: " + to_string(sepolicyVersion()) + " vs. " +
753                          to_string(other->sepolicyVersion());
754             }
755             return false;
756         }
757 
758         if (!mergeKernel(&other->device.mKernel, error)) {
759             return false;
760         }
761     } else if (type() == SchemaType::FRAMEWORK) {
762 #pragma clang diagnostic push
763 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
764         framework.mVndks.insert(framework.mVndks.end(), other->framework.mVndks.begin(),
765                                 other->framework.mVndks.end());
766         other->framework.mVndks.clear();
767 #pragma clang diagnostic pop
768 
769         framework.mVendorNdks.insert(framework.mVendorNdks.end(),
770                                      other->framework.mVendorNdks.begin(),
771                                      other->framework.mVendorNdks.end());
772         other->framework.mVendorNdks.clear();
773 
774         framework.mSystemSdk.addAll(&other->framework.mSystemSdk);
775     } else {
776         LOG(FATAL) << "unknown SchemaType: "
777                    << static_cast<std::underlying_type_t<SchemaType>>(type());
778     }
779 
780     if (!other->empty()) {
781         if (error) {
782             *error =
783                 "Cannot add another manifest because it contains extraneous entries that "
784                 "are not recognized.";
785         }
786         return false;
787     }
788 
789     return true;
790 }
791 
inferredKernelLevel() const792 Level HalManifest::inferredKernelLevel() const {
793     if (kernel().has_value()) {
794         if (kernel()->level() != Level::UNSPECIFIED) {
795             return kernel()->level();
796         }
797     }
798     // As a special case, for devices launching with R and above, also infer from <manifest>.level.
799     // Devices launching before R may leave kernel level unspecified to use legacy kernel
800     // matching behavior; see KernelInfo::getMatchedKernelRequirements.
801     if (level() >= Level::R) {
802         return level();
803     }
804     return Level::UNSPECIFIED;
805 }
806 
807 } // namespace vintf
808 } // namespace android
809