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 using details::mergeField;
40
41 // Check <version> tag for all <hal> with the same name.
shouldAdd(const ManifestHal & hal) const42 bool HalManifest::shouldAdd(const ManifestHal& hal) const {
43 if (!hal.isValid()) {
44 return false;
45 }
46 if (hal.isOverride()) {
47 return true;
48 }
49 auto existingHals = mHals.equal_range(hal.name);
50 std::set<size_t> existingMajorVersions;
51 for (auto it = existingHals.first; it != existingHals.second; ++it) {
52 for (const auto& v : it->second.versions) {
53 // Assume integrity on existingHals, so no check on emplace().second
54 existingMajorVersions.insert(v.majorVer);
55 }
56 }
57 for (const auto& v : hal.versions) {
58 if (!existingMajorVersions.emplace(v.majorVer).second /* no insertion */) {
59 return false;
60 }
61 }
62 return true;
63 }
64
65 // Remove elements from "list" if p(element) returns true.
66 template <typename List, typename Predicate>
removeIf(List & list,Predicate predicate)67 static void removeIf(List& list, Predicate predicate) {
68 for (auto it = list.begin(); it != list.end();) {
69 if (predicate(*it)) {
70 it = list.erase(it);
71 } else {
72 ++it;
73 }
74 }
75 }
76
removeHals(const std::string & name,size_t majorVer)77 void HalManifest::removeHals(const std::string& name, size_t majorVer) {
78 removeIf(mHals, [&name, majorVer](auto& existingHalPair) {
79 auto& existingHal = existingHalPair.second;
80 if (existingHal.name != name) {
81 return false;
82 }
83 auto& existingVersions = existingHal.versions;
84 removeIf(existingVersions, [majorVer](const auto& existingVersion) {
85 return existingVersion.majorVer == majorVer;
86 });
87 return existingVersions.empty();
88 });
89 }
90
add(ManifestHal && halToAdd)91 bool HalManifest::add(ManifestHal&& halToAdd) {
92 if (halToAdd.isOverride()) {
93 if (halToAdd.isDisabledHal()) {
94 // Special syntax when there are no instances at all. Remove all existing HALs
95 // with the given name.
96 mHals.erase(halToAdd.name);
97 }
98 // If there are <version> tags, remove all existing major versions that causes a conflict.
99 for (const Version& versionToAdd : halToAdd.versions) {
100 removeHals(halToAdd.name, versionToAdd.majorVer);
101 }
102 }
103
104 return HalGroup::add(std::move(halToAdd));
105 }
106
shouldAddXmlFile(const ManifestXmlFile & xmlFile) const107 bool HalManifest::shouldAddXmlFile(const ManifestXmlFile& xmlFile) const {
108 auto existingXmlFiles = getXmlFiles(xmlFile.name());
109 for (auto it = existingXmlFiles.first; it != existingXmlFiles.second; ++it) {
110 if (xmlFile.version() == it->second.version()) {
111 return false;
112 }
113 }
114 return true;
115 }
116
getHalNames() const117 std::set<std::string> HalManifest::getHalNames() const {
118 std::set<std::string> names{};
119 for (const auto &hal : mHals) {
120 names.insert(hal.first);
121 }
122 return names;
123 }
124
getHalNamesAndVersions() const125 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
126 std::set<std::string> names{};
127 forEachInstance([&names](const ManifestInstance& e) {
128 names.insert(toFQNameString(e.package(), e.version()));
129 return true;
130 });
131 return names;
132 }
133
getTransport(const std::string & package,const Version & v,const std::string & interfaceName,const std::string & instanceName) const134 Transport HalManifest::getTransport(const std::string &package, const Version &v,
135 const std::string &interfaceName, const std::string &instanceName) const {
136 Transport transport{Transport::EMPTY};
137 forEachInstanceOfInterface(package, v, interfaceName, [&](const auto& e) {
138 if (e.instance() == instanceName) {
139 transport = e.transport();
140 }
141 return transport == Transport::EMPTY; // if not found, continue
142 });
143 if (transport == Transport::EMPTY) {
144 LOG(DEBUG) << "HalManifest::getTransport(" << mType << "): Cannot find "
145 << toFQNameString(package, v, interfaceName, instanceName);
146 }
147 return transport;
148 }
149
forEachInstanceOfVersion(const std::string & package,const Version & expectVersion,const std::function<bool (const ManifestInstance &)> & func) const150 bool HalManifest::forEachInstanceOfVersion(
151 const std::string& package, const Version& expectVersion,
152 const std::function<bool(const ManifestInstance&)>& func) const {
153 for (const ManifestHal* hal : getHals(package)) {
154 bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
155 if (manifestInstance.version().minorAtLeast(expectVersion)) {
156 return func(manifestInstance);
157 }
158 return true;
159 });
160 if (!cont) return false;
161 }
162 return true;
163 }
164
165 // indent = 2, {"foo"} => "foo"
166 // indent = 2, {"foo", "bar"} => "\n foo\n bar";
167 template <typename Container>
multilineIndent(std::ostream & os,size_t indent,const Container & lines)168 void multilineIndent(std::ostream& os, size_t indent, const Container& lines) {
169 if (lines.size() == 1) {
170 os << *lines.begin();
171 return;
172 }
173 for (const auto& line : lines) {
174 os << "\n";
175 for (size_t i = 0; i < indent; ++i) os << " ";
176 os << line;
177 }
178 }
179
180 // For each hal in mat, there must be a hal in manifest that supports this.
checkIncompatibleHals(const CompatibilityMatrix & mat) const181 std::vector<std::string> HalManifest::checkIncompatibleHals(const CompatibilityMatrix& mat) const {
182 std::vector<std::string> ret;
183 for (const MatrixHal &matrixHal : mat.getHals()) {
184 if (matrixHal.optional) {
185 continue;
186 }
187
188 std::set<FqInstance> manifestInstances;
189 std::set<FqInstance> manifestInstancesNoPackage;
190 std::set<Version> versions;
191 for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
192 manifestHal->forEachInstance([&](const auto& manifestInstance) {
193 manifestInstances.insert(manifestInstance.getFqInstance());
194 manifestInstancesNoPackage.insert(manifestInstance.getFqInstanceNoPackage());
195 return true;
196 });
197 manifestHal->appendAllVersions(&versions);
198 }
199
200 if (!matrixHal.isCompatible(manifestInstances, versions)) {
201 std::ostringstream oss;
202 oss << matrixHal.name << ":\n required: ";
203 multilineIndent(oss, 8, android::vintf::expandInstances(matrixHal));
204 oss << "\n provided: ";
205 if (manifestInstances.empty()) {
206 multilineIndent(oss, 8, versions);
207 } else {
208 multilineIndent(oss, 8, manifestInstancesNoPackage);
209 }
210
211 ret.insert(ret.end(), oss.str());
212 }
213 }
214 return ret;
215 }
216
checkUnusedHals(const CompatibilityMatrix & mat) const217 std::set<std::string> HalManifest::checkUnusedHals(const CompatibilityMatrix& mat) const {
218 std::set<std::string> ret;
219
220 forEachInstance([&ret, &mat](const auto& manifestInstance) {
221 const auto& fqInstance = manifestInstance.getFqInstance();
222 if (!mat.matchInstance(fqInstance.getPackage(), fqInstance.getVersion(),
223 fqInstance.getInterface(), fqInstance.getInstance())) {
224 ret.insert(fqInstance.string());
225 }
226 return true;
227 });
228
229 return ret;
230 }
231
checkVendorNdkCompatibility(const VendorNdk & matVendorNdk,const std::vector<VendorNdk> & manifestVendorNdk,std::string * error)232 static bool checkVendorNdkCompatibility(const VendorNdk& matVendorNdk,
233 const std::vector<VendorNdk>& manifestVendorNdk,
234 std::string* error) {
235 // For pre-P vendor images, device compatibility matrix does not specify <vendor-ndk>
236 // tag. Ignore the check for these devices.
237 if (matVendorNdk.version().empty()) {
238 return true;
239 }
240 for (const auto& vndk : manifestVendorNdk) {
241 if (vndk.version() != matVendorNdk.version()) {
242 continue;
243 }
244 // version matches, check libraries
245 std::vector<std::string> diff;
246 std::set_difference(matVendorNdk.libraries().begin(), matVendorNdk.libraries().end(),
247 vndk.libraries().begin(), vndk.libraries().end(),
248 std::inserter(diff, diff.begin()));
249 if (!diff.empty()) {
250 if (error != nullptr) {
251 *error = "Vndk libs incompatible for version " + matVendorNdk.version() +
252 ". These libs are not in framework manifest:";
253 for (const auto& name : diff) {
254 *error += " " + name;
255 }
256 }
257 return false;
258 }
259 return true;
260 }
261
262 // no match is found.
263 if (error != nullptr) {
264 *error = "Vndk version " + matVendorNdk.version() + " is not supported. " +
265 "Supported versions in framework manifest are:";
266 for (const auto& vndk : manifestVendorNdk) {
267 *error += " " + vndk.version();
268 }
269 }
270 return false;
271 }
272
checkSystemSdkCompatibility(const SystemSdk & matSystemSdk,const SystemSdk & manifestSystemSdk,std::string * error)273 static bool checkSystemSdkCompatibility(const SystemSdk& matSystemSdk,
274 const SystemSdk& manifestSystemSdk, std::string* error) {
275 SystemSdk notSupported = matSystemSdk.removeVersions(manifestSystemSdk);
276 if (!notSupported.empty()) {
277 if (error) {
278 *error =
279 "The following System SDK versions are required by device "
280 "compatibility matrix but not supported by the framework manifest: [" +
281 base::Join(notSupported.versions(), ", ") + "]. Supported versions are: [" +
282 base::Join(manifestSystemSdk.versions(), ", ") + "].";
283 }
284 return false;
285 }
286 return true;
287 }
288
checkCompatibility(const CompatibilityMatrix & mat,std::string * error) const289 bool HalManifest::checkCompatibility(const CompatibilityMatrix &mat, std::string *error) const {
290 if (mType == mat.mType) {
291 if (error != nullptr) {
292 *error = "Wrong type; checking " + to_string(mType) + " manifest against "
293 + to_string(mat.mType) + " compatibility matrix";
294 }
295 return false;
296 }
297 auto incompatibleHals = checkIncompatibleHals(mat);
298 if (!incompatibleHals.empty()) {
299 if (error != nullptr) {
300 *error = "HALs incompatible.";
301 if (mat.level() != Level::UNSPECIFIED)
302 *error += " Matrix level = " + to_string(mat.level()) + ".";
303 if (level() != Level::UNSPECIFIED)
304 *error += " Manifest level = " + to_string(level()) + ".";
305 *error += " The following requirements are not met:\n";
306 for (const auto& e : incompatibleHals) {
307 *error += e + "\n";
308 }
309 }
310 return false;
311 }
312 if (mType == SchemaType::FRAMEWORK) {
313 if (!checkVendorNdkCompatibility(mat.device.mVendorNdk, framework.mVendorNdks, error)) {
314 return false;
315 }
316
317 if (!checkSystemSdkCompatibility(mat.device.mSystemSdk, framework.mSystemSdk, error)) {
318 return false;
319 }
320 } else if (mType == SchemaType::DEVICE) {
321 bool sepolicyMatch = false;
322 for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
323 if (range.supportedBy(device.mSepolicyVersion)) {
324 sepolicyMatch = true;
325 break;
326 }
327 }
328 if (!sepolicyMatch) {
329 if (error != nullptr) {
330 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
331 + " doesn't satisify the requirements.";
332 }
333 return false;
334 }
335
336 if (!!kernel() && !kernel()->matchKernelRequirements(mat.framework.mKernels, error)) {
337 return false;
338 }
339 }
340
341 return true;
342 }
343
generateCompatibleMatrix() const344 CompatibilityMatrix HalManifest::generateCompatibleMatrix() const {
345 CompatibilityMatrix matrix;
346
347 forEachInstance([&matrix](const ManifestInstance& e) {
348 matrix.add(MatrixHal{
349 .format = e.format(),
350 .name = e.package(),
351 .optional = true,
352 .versionRanges = {VersionRange{e.version().majorVer, e.version().minorVer}},
353 .interfaces = {{e.interface(), HalInterface{e.interface(), {e.instance()}}}}});
354 return true;
355 });
356 if (mType == SchemaType::FRAMEWORK) {
357 matrix.mType = SchemaType::DEVICE;
358 // VNDK does not need to be added for compatibility
359 } else if (mType == SchemaType::DEVICE) {
360 matrix.mType = SchemaType::FRAMEWORK;
361 matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
362 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
363 }
364
365 return matrix;
366 }
367
fetchAllInformation(const FileSystem * fileSystem,const std::string & path,std::string * error)368 status_t HalManifest::fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
369 std::string* error) {
370 return details::fetchAllInformation(fileSystem, path, gHalManifestConverter, this, error);
371 }
372
type() const373 SchemaType HalManifest::type() const {
374 return mType;
375 }
376
setType(SchemaType type)377 void HalManifest::setType(SchemaType type) {
378 mType = type;
379 }
380
level() const381 Level HalManifest::level() const {
382 return mLevel;
383 }
384
getMetaVersion() const385 Version HalManifest::getMetaVersion() const {
386 return mMetaVersion;
387 }
388
sepolicyVersion() const389 const Version &HalManifest::sepolicyVersion() const {
390 CHECK(mType == SchemaType::DEVICE);
391 return device.mSepolicyVersion;
392 }
393
vendorNdks() const394 const std::vector<VendorNdk>& HalManifest::vendorNdks() const {
395 CHECK(mType == SchemaType::FRAMEWORK);
396 return framework.mVendorNdks;
397 }
398
getXmlFilePath(const std::string & xmlFileName,const Version & version) const399 std::string HalManifest::getXmlFilePath(const std::string& xmlFileName,
400 const Version& version) const {
401 using std::literals::string_literals::operator""s;
402 auto range = getXmlFiles(xmlFileName);
403 for (auto it = range.first; it != range.second; ++it) {
404 const ManifestXmlFile& manifestXmlFile = it->second;
405 if (manifestXmlFile.version() == version) {
406 if (!manifestXmlFile.overriddenPath().empty()) {
407 return manifestXmlFile.overriddenPath();
408 }
409 return "/"s + (type() == SchemaType::DEVICE ? "vendor" : "system") + "/etc/" +
410 xmlFileName + "_V" + std::to_string(version.majorVer) + "_" +
411 std::to_string(version.minorVer) + ".xml";
412 }
413 }
414 return "";
415 }
416
operator ==(const HalManifest & lft,const HalManifest & rgt)417 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
418 return lft.mType == rgt.mType && lft.mLevel == rgt.mLevel && lft.mHals == rgt.mHals &&
419 lft.mXmlFiles == rgt.mXmlFiles &&
420 (lft.mType != SchemaType::DEVICE ||
421 (lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion &&
422 lft.device.mKernel == rgt.device.mKernel)) &&
423 (lft.mType != SchemaType::FRAMEWORK ||
424 (
425 #pragma clang diagnostic push
426 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
427 lft.framework.mVndks == rgt.framework.mVndks &&
428 #pragma clang diagnostic pop
429 lft.framework.mVendorNdks == rgt.framework.mVendorNdks &&
430 lft.framework.mSystemSdk == rgt.framework.mSystemSdk));
431 }
432
433 // 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) const434 std::set<std::string> HalManifest::getInstances(const std::string& halName, const Version& version,
435 const std::string& interfaceName) const {
436 std::set<std::string> ret;
437 (void)forEachInstanceOfInterface(halName, version, interfaceName, [&ret](const auto& e) {
438 ret.insert(e.instance());
439 return true;
440 });
441 return ret;
442 }
443
444 // Return whether instance is in getInstances(...).
hasInstance(const std::string & halName,const Version & version,const std::string & interfaceName,const std::string & instance) const445 bool HalManifest::hasInstance(const std::string& halName, const Version& version,
446 const std::string& interfaceName, const std::string& instance) const {
447 bool found = false;
448 (void)forEachInstanceOfInterface(halName, version, interfaceName,
449 [&found, &instance](const auto& e) {
450 found |= (instance == e.instance());
451 return !found; // if not found, continue
452 });
453 return found;
454 }
455
insertInstance(const FqInstance & fqInstance,Transport transport,Arch arch,HalFormat format,std::string * error)456 bool HalManifest::insertInstance(const FqInstance& fqInstance, Transport transport, Arch arch,
457 HalFormat format, std::string* error) {
458 for (ManifestHal& hal : getHals()) {
459 if (hal.name == fqInstance.getPackage() && hal.format == format &&
460 hal.transport() == transport && hal.arch() == arch) {
461 return hal.insertInstance(fqInstance, error);
462 }
463 }
464
465 ManifestHal hal;
466 hal.name = fqInstance.getPackage();
467 hal.format = format;
468 hal.transportArch = TransportArch(transport, arch);
469 if (!hal.insertInstance(fqInstance, error)) return false;
470 return add(std::move(hal));
471 }
472
empty() const473 bool HalManifest::empty() const {
474 HalManifest emptyManifest;
475 emptyManifest.setType(type());
476 return (*this) == emptyManifest;
477 }
478
kernel() const479 const std::optional<KernelInfo>& HalManifest::kernel() const {
480 return device.mKernel;
481 }
482
addAll(HalManifest * other,std::string * error)483 bool HalManifest::addAll(HalManifest* other, std::string* error) {
484 if (other->mMetaVersion.majorVer != mMetaVersion.majorVer) {
485 if (error) {
486 *error = "Cannot merge manifest version " + to_string(mMetaVersion) + " and " +
487 to_string(other->mMetaVersion);
488 }
489 return false;
490 }
491 mMetaVersion.minorVer = std::max(mMetaVersion.minorVer, other->mMetaVersion.minorVer);
492
493 if (type() != other->type()) {
494 if (error) {
495 *error = "Cannot add a " + to_string(other->type()) + " manifest to a " +
496 to_string(type()) + " manifest";
497 }
498 return false;
499 }
500
501 if (!addAllHals(other, error)) {
502 return false;
503 }
504
505 if (!addAllXmlFiles(other, error)) {
506 return false;
507 }
508
509 if (!mergeField(&mLevel, &other->mLevel, Level::UNSPECIFIED)) {
510 if (error) {
511 *error = "Conflicting target-level: " + to_string(level()) + " vs. " +
512 to_string(other->level());
513 }
514 return false;
515 }
516
517 if (type() == SchemaType::DEVICE) {
518 if (!mergeField(&device.mSepolicyVersion, &other->device.mSepolicyVersion)) {
519 if (error) {
520 *error = "Conflicting sepolicy version: " + to_string(sepolicyVersion()) + " vs. " +
521 to_string(other->sepolicyVersion());
522 }
523 return false;
524 }
525
526 if (!mergeField(&device.mKernel, &other->device.mKernel)) {
527 // If fails, both have values.
528 if (error) {
529 *error = "Conflicting kernel: " + to_string(device.mKernel->version()) + " vs. " +
530 to_string(other->device.mKernel->version());
531 }
532 return false;
533 }
534 } else if (type() == SchemaType::FRAMEWORK) {
535 #pragma clang diagnostic push
536 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
537 framework.mVndks.insert(framework.mVndks.end(), other->framework.mVndks.begin(),
538 other->framework.mVndks.end());
539 other->framework.mVndks.clear();
540 #pragma clang diagnostic pop
541
542 framework.mVendorNdks.insert(framework.mVendorNdks.end(),
543 other->framework.mVendorNdks.begin(),
544 other->framework.mVendorNdks.end());
545 other->framework.mVendorNdks.clear();
546
547 framework.mSystemSdk.addAll(&other->framework.mSystemSdk);
548 } else {
549 LOG(FATAL) << "unknown SchemaType: "
550 << static_cast<std::underlying_type_t<SchemaType>>(type());
551 }
552
553 if (!other->empty()) {
554 if (error) {
555 *error =
556 "Cannot add another manifest because it contains extraneous entries that "
557 "are not recognized.";
558 }
559 return false;
560 }
561
562 return true;
563 }
564
565 } // namespace vintf
566 } // namespace android
567