• 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 <mutex>
25 #include <set>
26 
27 #include <android-base/strings.h>
28 
29 #include "parse_string.h"
30 #include "parse_xml.h"
31 #include "utils.h"
32 #include "CompatibilityMatrix.h"
33 
34 namespace android {
35 namespace vintf {
36 
37 using details::Instances;
38 using details::InstancesOfVersion;
39 
40 // Check <version> tag for all <hal> with the same name.
shouldAdd(const ManifestHal & hal) const41 bool HalManifest::shouldAdd(const ManifestHal& hal) const {
42     if (!hal.isValid()) {
43         return false;
44     }
45     if (hal.isOverride()) {
46         return true;
47     }
48     auto existingHals = mHals.equal_range(hal.name);
49     std::set<size_t> existingMajorVersions;
50     for (auto it = existingHals.first; it != existingHals.second; ++it) {
51         for (const auto& v : it->second.versions) {
52             // Assume integrity on existingHals, so no check on emplace().second
53             existingMajorVersions.insert(v.majorVer);
54         }
55     }
56     for (const auto& v : hal.versions) {
57         if (!existingMajorVersions.emplace(v.majorVer).second /* no insertion */) {
58             return false;
59         }
60     }
61     return true;
62 }
63 
64 // Remove elements from "list" if p(element) returns true.
65 template <typename List, typename Predicate>
removeIf(List & list,Predicate predicate)66 static void removeIf(List& list, Predicate predicate) {
67     for (auto it = list.begin(); it != list.end();) {
68         if (predicate(*it)) {
69             it = list.erase(it);
70         } else {
71             ++it;
72         }
73     }
74 }
75 
removeHals(const std::string & name,size_t majorVer)76 void HalManifest::removeHals(const std::string& name, size_t majorVer) {
77     removeIf(mHals, [&name, majorVer](auto& existingHalPair) {
78         auto& existingHal = existingHalPair.second;
79         if (existingHal.name != name) {
80             return false;
81         }
82         auto& existingVersions = existingHal.versions;
83         removeIf(existingVersions, [majorVer](const auto& existingVersion) {
84             return existingVersion.majorVer == majorVer;
85         });
86         return existingVersions.empty();
87     });
88 }
89 
add(ManifestHal && halToAdd)90 bool HalManifest::add(ManifestHal&& halToAdd) {
91     if (halToAdd.isOverride()) {
92         if (halToAdd.isDisabledHal()) {
93             // Special syntax when there are no instances at all. Remove all existing HALs
94             // with the given name.
95             mHals.erase(halToAdd.name);
96         }
97         // If there are <version> tags, remove all existing major versions that causes a conflict.
98         for (const Version& versionToAdd : halToAdd.versions) {
99             removeHals(halToAdd.name, versionToAdd.majorVer);
100         }
101     }
102 
103     return HalGroup::add(std::move(halToAdd));
104 }
105 
shouldAddXmlFile(const ManifestXmlFile & xmlFile) const106 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const {
107     auto existingXmlFiles = getXmlFiles(xmlFile.name());
108     for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) {
109         if (xmlFile.version() == it->second.version()) {
110             return false;
111         }
112     }
113     return true;
114 }
115 
getHalNames() const116 std::set<std::string> HalManifest::getHalNames() const {
117     std::set<std::string> names{};
118     for (const auto &hal : mHals) {
119         names.insert(hal.first);
120     }
121     return names;
122 }
123 
getHalNamesAndVersions() const124 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
125     std::set<std::string> names{};
126     forEachInstance([&names](const ManifestInstance& e) {
127         names.insert(toFQNameString(e.interface(), e.version()));
128         return true;
129     });
130     return names;
131 }
132 
getTransport(const std::string & package,const Version & v,const std::string & interfaceName,const std::string & instanceName) const133 Transport HalManifest::getTransport(const std::string &package, const Version &v,
134             const std::string &interfaceName, const std::string &instanceName) const {
135     Transport transport{Transport::EMPTY};
136     forEachInstanceOfInterface(package, v, interfaceName, [&](const auto& e) {
137         if (e.instance() == instanceName) {
138             transport = e.transport();
139         }
140         return transport == Transport::EMPTY;  // if not found, continue
141     });
142     if (transport == Transport::EMPTY) {
143         LOG(DEBUG) << "HalManifest::getTransport(" << mType << "): Cannot find "
144                    << toFQNameString(package, v, interfaceName, instanceName);
145     }
146     return transport;
147 }
148 
forEachInstanceOfVersion(const std::string & package,const Version & expectVersion,const std::function<bool (const ManifestInstance &)> & func) const149 bool HalManifest::forEachInstanceOfVersion(
150     const std::string& package, const Version& expectVersion,
151     const std::function<bool(const ManifestInstance&)>& func) const {
152     for (const ManifestHal* hal : getHals(package)) {
153         bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
154             if (manifestInstance.version().minorAtLeast(expectVersion)) {
155                 return func(manifestInstance);
156             }
157             return true;
158         });
159         if (!cont) return false;
160     }
161     return true;
162 }
163 
164 // indent = 2, {"foo"} => "foo"
165 // indent = 2, {"foo", "bar"} => "\n  foo\n  bar";
166 template <typename Container>
multilineIndent(std::ostream & os,size_t indent,const Container & lines)167 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) {
168     if (lines.size() == 1) {
169         os << *lines.begin();
170         return;
171     }
172     for (const auto& line : lines) {
173         os << "\n";
174         for (size_t i = 0; i < indent; ++i) os << " ";
175         os << line;
176     }
177 }
178 
179 // For each hal in mat, there must be a hal in manifest that supports this.
checkIncompatibleHals(const CompatibilityMatrix & mat) const180 std::vector<std::string> HalManifest::checkIncompatibleHals(const CompatibilityMatrix& mat) const {
181     std::vector<std::string> ret;
182     for (const MatrixHal &matrixHal : mat.getHals()) {
183         if (matrixHal.optional) {
184             continue;
185         }
186 
187         std::set<FqInstance> manifestInstances;
188         std::set<FqInstance> manifestInstancesNoPackage;
189         std::set<Version> versions;
190         for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
191             manifestHal->forEachInstance([&](const auto& manifestInstance) {
192                 manifestInstances.insert(manifestInstance.getFqInstance());
193                 manifestInstancesNoPackage.insert(manifestInstance.getFqInstanceNoPackage());
194                 return true;
195             });
196             manifestHal->appendAllVersions(&versions);
197         }
198 
199         if (!matrixHal.isCompatible(manifestInstances, versions)) {
200             std::ostringstream oss;
201             oss << matrixHal.name << ":\n    required: ";
202             multilineIndent(oss, 8, android::vintf::expandInstances(matrixHal));
203             oss << "\n    provided: ";
204             if (manifestInstances.empty()) {
205                 multilineIndent(oss, 8, versions);
206             } else {
207                 multilineIndent(oss, 8, manifestInstancesNoPackage);
208             }
209 
210             ret.insert(ret.end(), oss.str());
211         }
212     }
213     return ret;
214 }
215 
checkUnusedHals(const CompatibilityMatrix & mat) const216 std::set<std::string> HalManifest::checkUnusedHals(const CompatibilityMatrix& mat) const {
217     std::set<std::string> ret;
218 
219     forEachInstance([&ret, &mat](const auto& manifestInstance) {
220         const auto& fqInstance = manifestInstance.getFqInstance();
221         if (!mat.matchInstance(fqInstance.getPackage(), fqInstance.getVersion(),
222                                fqInstance.getInterface(), fqInstance.getInstance())) {
223             ret.insert(fqInstance.string());
224         }
225         return true;
226     });
227 
228     return ret;
229 }
230 
checkVendorNdkCompatibility(const VendorNdk & matVendorNdk,const std::vector<VendorNdk> & manifestVendorNdk,std::string * error)231 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
232                                         const std::vector<VendorNdk>& manifestVendorNdk,
233                                         std::string* error) {
234     // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
235     // tag. Ignore the check for these devices.
236     if (matVendorNdk.version().empty()) {
237         return true;
238     }
239     for (const auto& vndk : manifestVendorNdk) {
240         if (vndk.version() != matVendorNdk.version()) {
241             continue;
242         }
243         // version matches, check libraries
244         std::vector<std::string> diff;
245         std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
246                             vndk.libraries().begin(), vndk.libraries().end(),
247                             std::inserter(diff, diff.begin()));
248         if (!diff.empty()) {
249             if (error != nullptr) {
250                 *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
251                          ". These libs are not in framework manifest:";
252                 for (const auto& name : diff) {
253                     *error += " " + name;
254                 }
255             }
256             return false;
257         }
258         return true;
259     }
260 
261     // no match is found.
262     if (error != nullptr) {
263         *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
264                  "Supported versions in framework manifest are:";
265         for (const auto& vndk : manifestVendorNdk) {
266             *error += " " + vndk.version();
267         }
268     }
269     return false;
270 }
271 
checkSystemSdkCompatibility(const SystemSdk & matSystemSdk,const SystemSdk & manifestSystemSdk,std::string * error)272 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk,
273                                         const SystemSdk& manifestSystemSdk, std::string* error) {
274     SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk);
275     if (!notSupported.empty()) {
276         if (error) {
277             *error =
278                 "The following System SDK versions are required by device "
279                 "compatibility matrix but not supported by the framework manifest: [" +
280                 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" +
281                 base::Join(manifestSystemSdk.versions(), ", ") + "].";
282         }
283         return false;
284     }
285     return true;
286 }
287 
checkCompatibility(const CompatibilityMatrix & mat,std::string * error) const288 bool HalManifest::checkCompatibility(const CompatibilityMatrix &mat, std::string *error) const {
289     if (mType == mat.mType) {
290         if (error != nullptr) {
291             *error = "Wrong type; checking " + to_string(mType) + " manifest against "
292                     + to_string(mat.mType) + " compatibility matrix";
293         }
294         return false;
295     }
296     auto incompatibleHals = checkIncompatibleHals(mat);
297     if (!incompatibleHals.empty()) {
298         if (error != nullptr) {
299             *error = "HALs incompatible.";
300             if (mat.level() != Level::UNSPECIFIED)
301                 *error += " Matrix level = " + to_string(mat.level()) + ".";
302             if (level() != Level::UNSPECIFIED)
303                 *error += " Manifest level = " + to_string(level()) + ".";
304             *error += " The following requirements are not met:\n";
305             for (const auto& e : incompatibleHals) {
306                 *error += e + "\n";
307             }
308         }
309         return false;
310     }
311     if (mType == SchemaType::FRAMEWORK) {
312         if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
313             return false;
314         }
315 
316         if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) {
317             return false;
318         }
319     } else if (mType == SchemaType::DEVICE) {
320         bool match = false;
321         for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
322             if (range.supportedBy(device.mSepolicyVersion)) {
323                 match = true;
324                 break;
325             }
326         }
327         if (!match) {
328             if (error != nullptr) {
329                 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
330                         + " doesn't satisify the requirements.";
331             }
332             return false;
333         }
334     }
335 
336     return true;
337 }
338 
generateCompatibleMatrix() const339 CompatibilityMatrix HalManifest::generateCompatibleMatrix() const {
340     CompatibilityMatrix matrix;
341 
342     forEachInstance([&matrix](const ManifestInstance& e) {
343         matrix.add(MatrixHal{
344             .format = e.format(),
345             .name = e.package(),
346             .optional = true,
347             .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}},
348             .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}});
349         return true;
350     });
351     if (mType == SchemaType::FRAMEWORK) {
352         matrix.mType = SchemaType::DEVICE;
353         // VNDK does not need to be added for compatibility
354     } else if (mType == SchemaType::DEVICE) {
355         matrix.mType = SchemaType::FRAMEWORK;
356         matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
357                 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
358     }
359 
360     return matrix;
361 }
362 
fetchAllInformation(const std::string & path,std::string * error)363 status_t HalManifest::fetchAllInformation(const std::string& path, std::string* error) {
364     return details::fetchAllInformation(path, gHalManifestConverter, this, error);
365 }
366 
type() const367 SchemaType HalManifest::type() const {
368     return mType;
369 }
370 
setType(SchemaType type)371 void HalManifest::setType(SchemaType type) {
372     mType = type;
373 }
374 
level() const375 Level HalManifest::level() const {
376     return mLevel;
377 }
378 
getMetaVersion() const379 Version HalManifest::getMetaVersion() const {
380     return mMetaVersion;
381 }
382 
sepolicyVersion() const383 const Version &HalManifest::sepolicyVersion() const {
384     CHECK(mType == SchemaType::DEVICE);
385     return device.mSepolicyVersion;
386 }
387 
vendorNdks() const388 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
389     CHECK(mType == SchemaType::FRAMEWORK);
390     return framework.mVendorNdks;
391 }
392 
getXmlFilePath(const std::string & xmlFileName,const Version & version) const393 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
394                                         const Version& version) const {
395     using std::literals::string_literals::operator""s;
396     auto range = getXmlFiles(xmlFileName);
397     for (auto it = range.first; it != range.second; ++it) {
398         const ManifestXmlFile& manifestXmlFile = it->second;
399         if (manifestXmlFile.version() == version) {
400             if (!manifestXmlFile.overriddenPath().empty()) {
401                 return manifestXmlFile.overriddenPath();
402             }
403             return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
404                    xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
405                    std::to_string(version.minorVer) + ".xml";
406         }
407     }
408     return "";
409 }
410 
operator ==(const HalManifest & lft,const HalManifest & rgt)411 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
412     return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
413            lft.mXmlFiles == rgt.mXmlFiles &&
414            (lft.mType != SchemaType::DEVICE ||
415             (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) &&
416            (lft.mType != SchemaType::FRAMEWORK ||
417             (
418 #pragma clang diagnostic push
419 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
420                 lft.framework.mVndks == rgt.framework.mVndks &&
421 #pragma clang diagnostic pop
422                 lft.framework.mVendorNdks == rgt.framework.mVendorNdks &&
423                 lft.framework.mSystemSdk == rgt.framework.mSystemSdk));
424 }
425 
426 // Alternative to forEachInstance if you just need a set of instance names instead.
getInstances(const std::string & halName,const Version & version,const std::string & interfaceName) const427 std::set<std::string> HalManifest::getInstances(const std::string& halName, const Version& version,
428                                                 const std::string& interfaceName) const {
429     std::set<std::string> ret;
430     (void)forEachInstanceOfInterface(halName, version, interfaceName, [&ret](const auto& e) {
431         ret.insert(e.instance());
432         return true;
433     });
434     return ret;
435 }
436 
437 // Return whether instance is in getInstances(...).
hasInstance(const std::string & halName,const Version & version,const std::string & interfaceName,const std::string & instance) const438 bool HalManifest::hasInstance(const std::string& halName, const Version& version,
439                               const std::string& interfaceName, const std::string& instance) const {
440     bool found = false;
441     (void)forEachInstanceOfInterface(halName, version, interfaceName,
442                                      [&found, &instance](const auto& e) {
443                                          found |= (instance == e.instance());
444                                          return !found;  // if not found, continue
445                                      });
446     return found;
447 }
448 
449 } // namespace vintf
450 } // namespace android
451