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