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 #include "VintfObject.h" 18 19 #include <dirent.h> 20 21 #include <algorithm> 22 #include <functional> 23 #include <memory> 24 #include <mutex> 25 26 #include <android-base/logging.h> 27 #include <android-base/result.h> 28 #include <android-base/strings.h> 29 #include <hidl/metadata.h> 30 31 #include "CompatibilityMatrix.h" 32 #include "parse_string.h" 33 #include "parse_xml.h" 34 #include "utils.h" 35 36 using std::placeholders::_1; 37 using std::placeholders::_2; 38 39 namespace android { 40 namespace vintf { 41 42 using namespace details; 43 44 #ifdef LIBVINTF_TARGET 45 static constexpr bool kIsTarget = true; 46 #else 47 static constexpr bool kIsTarget = false; 48 #endif 49 50 template <typename T, typename F> 51 static std::shared_ptr<const T> Get(const char* id, LockedSharedPtr<T>* ptr, bool skipCache, 52 const F& fetchAllInformation) { 53 std::unique_lock<std::mutex> _lock(ptr->mutex); 54 if (skipCache || !ptr->fetchedOnce) { 55 LOG(INFO) << id << ": Reading VINTF information."; 56 ptr->object = std::make_unique<T>(); 57 std::string error; 58 status_t status = fetchAllInformation(ptr->object.get(), &error); 59 if (status == OK) { 60 ptr->fetchedOnce = true; 61 LOG(INFO) << id << ": Successfully processed VINTF information"; 62 } else { 63 // Doubled because a malformed error std::string might cause us to 64 // lose the status. 65 LOG(ERROR) << id << ": status from fetching VINTF information: " << status; 66 LOG(ERROR) << id << ": " << status << " VINTF parse error: " << error; 67 ptr->object = nullptr; // frees the old object 68 } 69 } 70 return ptr->object; 71 } 72 73 static std::unique_ptr<FileSystem> createDefaultFileSystem() { 74 std::unique_ptr<FileSystem> fileSystem; 75 if (kIsTarget) { 76 fileSystem = std::make_unique<details::FileSystemImpl>(); 77 } else { 78 fileSystem = std::make_unique<details::FileSystemNoOp>(); 79 } 80 return fileSystem; 81 } 82 83 static std::unique_ptr<PropertyFetcher> createDefaultPropertyFetcher() { 84 std::unique_ptr<PropertyFetcher> propertyFetcher; 85 if (kIsTarget) { 86 propertyFetcher = std::make_unique<details::PropertyFetcherImpl>(); 87 } else { 88 propertyFetcher = std::make_unique<details::PropertyFetcherNoOp>(); 89 } 90 return propertyFetcher; 91 } 92 93 std::shared_ptr<VintfObject> VintfObject::GetInstance() { 94 static details::LockedSharedPtr<VintfObject> sInstance{}; 95 std::unique_lock<std::mutex> lock(sInstance.mutex); 96 if (sInstance.object == nullptr) { 97 sInstance.object = std::shared_ptr<VintfObject>(VintfObject::Builder().build().release()); 98 } 99 return sInstance.object; 100 } 101 102 std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest(bool skipCache) { 103 return GetInstance()->getDeviceHalManifest(skipCache); 104 } 105 106 std::shared_ptr<const HalManifest> VintfObject::getDeviceHalManifest(bool skipCache) { 107 return Get(__func__, &mDeviceManifest, skipCache, 108 std::bind(&VintfObject::fetchDeviceHalManifest, this, _1, _2)); 109 } 110 111 std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest(bool skipCache) { 112 return GetInstance()->getFrameworkHalManifest(skipCache); 113 } 114 115 std::shared_ptr<const HalManifest> VintfObject::getFrameworkHalManifest(bool skipCache) { 116 return Get(__func__, &mFrameworkManifest, skipCache, 117 std::bind(&VintfObject::fetchFrameworkHalManifest, this, _1, _2)); 118 } 119 120 std::shared_ptr<const CompatibilityMatrix> VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) { 121 return GetInstance()->getDeviceCompatibilityMatrix(skipCache); 122 } 123 124 std::shared_ptr<const CompatibilityMatrix> VintfObject::getDeviceCompatibilityMatrix( 125 bool skipCache) { 126 return Get(__func__, &mDeviceMatrix, skipCache, 127 std::bind(&VintfObject::fetchDeviceMatrix, this, _1, _2)); 128 } 129 130 std::shared_ptr<const CompatibilityMatrix> VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) { 131 return GetInstance()->getFrameworkCompatibilityMatrix(skipCache); 132 } 133 134 std::shared_ptr<const CompatibilityMatrix> VintfObject::getFrameworkCompatibilityMatrix( 135 bool skipCache) { 136 // To avoid deadlock, get device manifest before any locks. 137 auto deviceManifest = getDeviceHalManifest(); 138 139 std::unique_lock<std::mutex> _lock(mFrameworkCompatibilityMatrixMutex); 140 141 auto combined = 142 Get(__func__, &mCombinedFrameworkMatrix, skipCache, 143 std::bind(&VintfObject::getCombinedFrameworkMatrix, this, deviceManifest, _1, _2)); 144 if (combined != nullptr) { 145 return combined; 146 } 147 148 return Get(__func__, &mFrameworkMatrix, skipCache, 149 std::bind(&CompatibilityMatrix::fetchAllInformation, _1, getFileSystem().get(), 150 kSystemLegacyMatrix, _2)); 151 } 152 153 status_t VintfObject::getCombinedFrameworkMatrix( 154 const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out, 155 std::string* error) { 156 std::vector<Named<CompatibilityMatrix>> matrixFragments; 157 auto matrixFragmentsStatus = getAllFrameworkMatrixLevels(&matrixFragments, error); 158 if (matrixFragmentsStatus != OK) { 159 return matrixFragmentsStatus; 160 } 161 if (matrixFragments.empty()) { 162 if (error && error->empty()) { 163 *error = "Cannot get framework matrix for each FCM version for unknown error."; 164 } 165 return NAME_NOT_FOUND; 166 } 167 168 Level deviceLevel = Level::UNSPECIFIED; 169 170 if (deviceManifest != nullptr) { 171 deviceLevel = deviceManifest->level(); 172 } 173 174 // TODO(b/70628538): Do not infer from Shipping API level. 175 if (deviceLevel == Level::UNSPECIFIED) { 176 auto shippingApi = getPropertyFetcher()->getUintProperty("ro.product.first_api_level", 0u); 177 if (shippingApi != 0u) { 178 deviceLevel = details::convertFromApiLevel(shippingApi); 179 } 180 } 181 182 if (deviceLevel == Level::UNSPECIFIED) { 183 // Cannot infer FCM version. Combine all matrices by assuming 184 // Shipping FCM Version == min(all supported FCM Versions in the framework) 185 for (auto&& pair : matrixFragments) { 186 Level fragmentLevel = pair.object.level(); 187 if (fragmentLevel != Level::UNSPECIFIED && deviceLevel > fragmentLevel) { 188 deviceLevel = fragmentLevel; 189 } 190 } 191 } 192 193 if (deviceLevel == Level::UNSPECIFIED) { 194 // None of the fragments specify any FCM version. Should never happen except 195 // for inconsistent builds. 196 if (error) { 197 *error = "No framework compatibility matrix files under " + kSystemVintfDir + 198 " declare FCM version."; 199 } 200 return NAME_NOT_FOUND; 201 } 202 203 auto combined = CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error); 204 if (combined == nullptr) { 205 return BAD_VALUE; 206 } 207 *out = std::move(*combined); 208 return OK; 209 } 210 211 // Load and combine all of the manifests in a directory 212 status_t VintfObject::addDirectoryManifests(const std::string& directory, HalManifest* manifest, 213 std::string* error) { 214 std::vector<std::string> fileNames; 215 status_t err = getFileSystem()->listFiles(directory, &fileNames, error); 216 // if the directory isn't there, that's okay 217 if (err == NAME_NOT_FOUND) return OK; 218 if (err != OK) return err; 219 220 for (const std::string& file : fileNames) { 221 // Only adds HALs because all other things are added by libvintf 222 // itself for now. 223 HalManifest fragmentManifest; 224 err = fetchOneHalManifest(directory + file, &fragmentManifest, error); 225 if (err != OK) return err; 226 227 if (!manifest->addAll(&fragmentManifest, error)) { 228 if (error) { 229 error->insert(0, "Cannot add manifest fragment " + directory + file + ":"); 230 } 231 return UNKNOWN_ERROR; 232 } 233 } 234 235 return OK; 236 } 237 238 // Priority for loading vendor manifest: 239 // 1. Vendor manifest + device fragments + ODM manifest (optional) + odm fragments 240 // 2. Vendor manifest + device fragments 241 // 3. ODM manifest (optional) + odm fragments 242 // 4. /vendor/manifest.xml (legacy, no fragments) 243 // where: 244 // A + B means unioning <hal> tags from A and B. If B declares an override, then this takes priority 245 // over A. 246 status_t VintfObject::fetchDeviceHalManifest(HalManifest* out, std::string* error) { 247 HalManifest vendorManifest; 248 status_t vendorStatus = fetchVendorHalManifest(&vendorManifest, error); 249 if (vendorStatus != OK && vendorStatus != NAME_NOT_FOUND) { 250 return vendorStatus; 251 } 252 253 if (vendorStatus == OK) { 254 *out = std::move(vendorManifest); 255 status_t fragmentStatus = addDirectoryManifests(kVendorManifestFragmentDir, out, error); 256 if (fragmentStatus != OK) { 257 return fragmentStatus; 258 } 259 } 260 261 HalManifest odmManifest; 262 status_t odmStatus = fetchOdmHalManifest(&odmManifest, error); 263 if (odmStatus != OK && odmStatus != NAME_NOT_FOUND) { 264 return odmStatus; 265 } 266 267 if (vendorStatus == OK) { 268 if (odmStatus == OK) { 269 if (!out->addAll(&odmManifest, error)) { 270 if (error) { 271 error->insert(0, "Cannot add ODM manifest :"); 272 } 273 return UNKNOWN_ERROR; 274 } 275 } 276 return addDirectoryManifests(kOdmManifestFragmentDir, out, error); 277 } 278 279 // vendorStatus != OK, "out" is not changed. 280 if (odmStatus == OK) { 281 *out = std::move(odmManifest); 282 return addDirectoryManifests(kOdmManifestFragmentDir, out, error); 283 } 284 285 // Use legacy /vendor/manifest.xml 286 return out->fetchAllInformation(getFileSystem().get(), kVendorLegacyManifest, error); 287 } 288 289 // Priority: 290 // 1. if {vendorSku} is defined, /vendor/etc/vintf/manifest_{vendorSku}.xml 291 // 2. /vendor/etc/vintf/manifest.xml 292 // where: 293 // {vendorSku} is the value of ro.boot.product.vendor.sku 294 status_t VintfObject::fetchVendorHalManifest(HalManifest* out, std::string* error) { 295 status_t status; 296 297 std::string vendorSku; 298 vendorSku = getPropertyFetcher()->getProperty("ro.boot.product.vendor.sku", ""); 299 300 if (!vendorSku.empty()) { 301 status = 302 fetchOneHalManifest(kVendorVintfDir + "manifest_" + vendorSku + ".xml", out, error); 303 if (status == OK || status != NAME_NOT_FOUND) { 304 return status; 305 } 306 } 307 308 status = fetchOneHalManifest(kVendorManifest, out, error); 309 if (status == OK || status != NAME_NOT_FOUND) { 310 return status; 311 } 312 313 return NAME_NOT_FOUND; 314 } 315 316 // "out" is written to iff return status is OK. 317 // Priority: 318 // 1. if {sku} is defined, /odm/etc/vintf/manifest_{sku}.xml 319 // 2. /odm/etc/vintf/manifest.xml 320 // 3. if {sku} is defined, /odm/etc/manifest_{sku}.xml 321 // 4. /odm/etc/manifest.xml 322 // where: 323 // {sku} is the value of ro.boot.product.hardware.sku 324 status_t VintfObject::fetchOdmHalManifest(HalManifest* out, std::string* error) { 325 status_t status; 326 327 std::string productModel; 328 productModel = getPropertyFetcher()->getProperty("ro.boot.product.hardware.sku", ""); 329 330 if (!productModel.empty()) { 331 status = 332 fetchOneHalManifest(kOdmVintfDir + "manifest_" + productModel + ".xml", out, error); 333 if (status == OK || status != NAME_NOT_FOUND) { 334 return status; 335 } 336 } 337 338 status = fetchOneHalManifest(kOdmManifest, out, error); 339 if (status == OK || status != NAME_NOT_FOUND) { 340 return status; 341 } 342 343 if (!productModel.empty()) { 344 status = fetchOneHalManifest(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml", out, 345 error); 346 if (status == OK || status != NAME_NOT_FOUND) { 347 return status; 348 } 349 } 350 351 status = fetchOneHalManifest(kOdmLegacyManifest, out, error); 352 if (status == OK || status != NAME_NOT_FOUND) { 353 return status; 354 } 355 356 return NAME_NOT_FOUND; 357 } 358 359 // Fetch one manifest.xml file. "out" is written to iff return status is OK. 360 // Returns NAME_NOT_FOUND if file is missing. 361 status_t VintfObject::fetchOneHalManifest(const std::string& path, HalManifest* out, 362 std::string* error) { 363 HalManifest ret; 364 status_t status = ret.fetchAllInformation(getFileSystem().get(), path, error); 365 if (status == OK) { 366 *out = std::move(ret); 367 } 368 return status; 369 } 370 371 status_t VintfObject::fetchDeviceMatrix(CompatibilityMatrix* out, std::string* error) { 372 CompatibilityMatrix etcMatrix; 373 if (etcMatrix.fetchAllInformation(getFileSystem().get(), kVendorMatrix, error) == OK) { 374 *out = std::move(etcMatrix); 375 return OK; 376 } 377 return out->fetchAllInformation(getFileSystem().get(), kVendorLegacyMatrix, error); 378 } 379 380 // Priority: 381 // 1. /system/etc/vintf/manifest.xml 382 // + /system/etc/vintf/manifest/*.xml if they exist 383 // + /product/etc/vintf/manifest.xml if it exists 384 // + /product/etc/vintf/manifest/*.xml if they exist 385 // 2. (deprecated) /system/manifest.xml 386 status_t VintfObject::fetchFrameworkHalManifest(HalManifest* out, std::string* error) { 387 auto systemEtcStatus = fetchOneHalManifest(kSystemManifest, out, error); 388 if (systemEtcStatus == OK) { 389 auto dirStatus = addDirectoryManifests(kSystemManifestFragmentDir, out, error); 390 if (dirStatus != OK) { 391 return dirStatus; 392 } 393 394 std::vector<std::pair<const std::string&, const std::string&>> extensions{ 395 {kProductManifest, kProductManifestFragmentDir}, 396 {kSystemExtManifest, kSystemExtManifestFragmentDir}, 397 }; 398 for (auto&& [manifestPath, frags] : extensions) { 399 HalManifest halManifest; 400 auto status = fetchOneHalManifest(manifestPath, &halManifest, error); 401 if (status != OK && status != NAME_NOT_FOUND) { 402 return status; 403 } 404 if (status == OK) { 405 if (!out->addAll(&halManifest, error)) { 406 if (error) { 407 error->insert(0, "Cannot add " + manifestPath + ":"); 408 } 409 return UNKNOWN_ERROR; 410 } 411 } 412 413 auto fragmentStatus = addDirectoryManifests(frags, out, error); 414 if (fragmentStatus != OK) { 415 return fragmentStatus; 416 } 417 } 418 return OK; 419 } else { 420 LOG(WARNING) << "Cannot fetch " << kSystemManifest << ": " 421 << (error ? *error : strerror(-systemEtcStatus)); 422 } 423 424 return out->fetchAllInformation(getFileSystem().get(), kSystemLegacyManifest, error); 425 } 426 427 static void appendLine(std::string* error, const std::string& message) { 428 if (error != nullptr) { 429 if (!error->empty()) *error += "\n"; 430 *error += message; 431 } 432 } 433 434 status_t VintfObject::getOneMatrix(const std::string& path, Named<CompatibilityMatrix>* out, 435 std::string* error) { 436 std::string content; 437 status_t status = getFileSystem()->fetch(path, &content, error); 438 if (status != OK) { 439 return status; 440 } 441 if (!gCompatibilityMatrixConverter(&out->object, content, error)) { 442 if (error) { 443 error->insert(0, "Cannot parse " + path + ": "); 444 } 445 return BAD_VALUE; 446 } 447 out->name = path; 448 return OK; 449 } 450 451 status_t VintfObject::getAllFrameworkMatrixLevels(std::vector<Named<CompatibilityMatrix>>* results, 452 std::string* error) { 453 std::vector<std::string> dirs = { 454 kSystemVintfDir, 455 kSystemExtVintfDir, 456 kProductVintfDir, 457 }; 458 for (const auto& dir : dirs) { 459 std::vector<std::string> fileNames; 460 status_t listStatus = getFileSystem()->listFiles(dir, &fileNames, error); 461 if (listStatus == NAME_NOT_FOUND) { 462 continue; 463 } 464 if (listStatus != OK) { 465 return listStatus; 466 } 467 for (const std::string& fileName : fileNames) { 468 std::string path = dir + fileName; 469 Named<CompatibilityMatrix> namedMatrix; 470 std::string matrixError; 471 status_t matrixStatus = getOneMatrix(path, &namedMatrix, &matrixError); 472 if (matrixStatus != OK) { 473 // Manifests and matrices share the same dir. Client may not have enough 474 // permissions to read system manifests, or may not be able to parse it. 475 auto logLevel = matrixStatus == BAD_VALUE ? base::DEBUG : base::ERROR; 476 LOG(logLevel) << "Framework Matrix: Ignore file " << path << ": " << matrixError; 477 continue; 478 } 479 results->emplace_back(std::move(namedMatrix)); 480 } 481 482 if (dir == kSystemVintfDir && results->empty()) { 483 if (error) { 484 *error = "No framework matrices under " + dir + " can be fetched or parsed.\n"; 485 } 486 return NAME_NOT_FOUND; 487 } 488 } 489 490 if (results->empty()) { 491 if (error) { 492 *error = 493 "No framework matrices can be fetched or parsed. " 494 "The following directories are searched:\n " + 495 android::base::Join(dirs, "\n "); 496 } 497 return NAME_NOT_FOUND; 498 } 499 return OK; 500 } 501 502 std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache, 503 RuntimeInfo::FetchFlags flags) { 504 return GetInstance()->getRuntimeInfo(skipCache, flags); 505 } 506 std::shared_ptr<const RuntimeInfo> VintfObject::getRuntimeInfo(bool skipCache, 507 RuntimeInfo::FetchFlags flags) { 508 std::unique_lock<std::mutex> _lock(mDeviceRuntimeInfo.mutex); 509 510 if (!skipCache) { 511 flags &= (~mDeviceRuntimeInfo.fetchedFlags); 512 } 513 514 if (mDeviceRuntimeInfo.object == nullptr) { 515 mDeviceRuntimeInfo.object = getRuntimeInfoFactory()->make_shared(); 516 } 517 518 // Fetch kernel FCM version from device HAL manifest and store it in RuntimeInfo too. 519 if ((flags & RuntimeInfo::FetchFlag::KERNEL_FCM) != 0) { 520 auto manifest = getDeviceHalManifest(); 521 if (!manifest) { 522 mDeviceRuntimeInfo.fetchedFlags &= ~RuntimeInfo::FetchFlag::KERNEL_FCM; 523 return nullptr; 524 } 525 Level level = Level::UNSPECIFIED; 526 if (manifest->kernel().has_value()) { 527 level = manifest->kernel()->level(); 528 } 529 mDeviceRuntimeInfo.object->setKernelLevel(level); 530 flags &= ~RuntimeInfo::FetchFlag::KERNEL_FCM; 531 } 532 533 status_t status = mDeviceRuntimeInfo.object->fetchAllInformation(flags); 534 if (status != OK) { 535 mDeviceRuntimeInfo.fetchedFlags &= (~flags); // mark the fields as "not fetched" 536 return nullptr; 537 } 538 539 mDeviceRuntimeInfo.fetchedFlags |= flags; 540 return mDeviceRuntimeInfo.object; 541 } 542 543 int32_t VintfObject::checkCompatibility(std::string* error, CheckFlags::Type flags) { 544 status_t status = OK; 545 // null checks for files and runtime info 546 if (getFrameworkHalManifest() == nullptr) { 547 appendLine(error, "No framework manifest file from device or from update package"); 548 status = NO_INIT; 549 } 550 if (getDeviceHalManifest() == nullptr) { 551 appendLine(error, "No device manifest file from device or from update package"); 552 status = NO_INIT; 553 } 554 if (getFrameworkCompatibilityMatrix() == nullptr) { 555 appendLine(error, "No framework matrix file from device or from update package"); 556 status = NO_INIT; 557 } 558 if (getDeviceCompatibilityMatrix() == nullptr) { 559 appendLine(error, "No device matrix file from device or from update package"); 560 status = NO_INIT; 561 } 562 563 if (flags.isRuntimeInfoEnabled()) { 564 if (getRuntimeInfo() == nullptr) { 565 appendLine(error, "No runtime info from device"); 566 status = NO_INIT; 567 } 568 } 569 if (status != OK) return status; 570 571 // compatiblity check. 572 if (!getDeviceHalManifest()->checkCompatibility(*getFrameworkCompatibilityMatrix(), error)) { 573 if (error) { 574 error->insert(0, 575 "Device manifest and framework compatibility matrix are incompatible: "); 576 } 577 return INCOMPATIBLE; 578 } 579 if (!getFrameworkHalManifest()->checkCompatibility(*getDeviceCompatibilityMatrix(), error)) { 580 if (error) { 581 error->insert(0, 582 "Framework manifest and device compatibility matrix are incompatible: "); 583 } 584 return INCOMPATIBLE; 585 } 586 587 if (flags.isRuntimeInfoEnabled()) { 588 if (!getRuntimeInfo()->checkCompatibility(*getFrameworkCompatibilityMatrix(), error, 589 flags)) { 590 if (error) { 591 error->insert(0, 592 "Runtime info and framework compatibility matrix are incompatible: "); 593 } 594 return INCOMPATIBLE; 595 } 596 } 597 598 return COMPATIBLE; 599 } 600 601 namespace details { 602 603 const std::string kSystemVintfDir = "/system/etc/vintf/"; 604 const std::string kVendorVintfDir = "/vendor/etc/vintf/"; 605 const std::string kOdmVintfDir = "/odm/etc/vintf/"; 606 const std::string kProductVintfDir = "/product/etc/vintf/"; 607 const std::string kSystemExtVintfDir = "/system_ext/etc/vintf/"; 608 609 const std::string kVendorManifest = kVendorVintfDir + "manifest.xml"; 610 const std::string kSystemManifest = kSystemVintfDir + "manifest.xml"; 611 const std::string kVendorMatrix = kVendorVintfDir + "compatibility_matrix.xml"; 612 const std::string kOdmManifest = kOdmVintfDir + "manifest.xml"; 613 const std::string kProductMatrix = kProductVintfDir + "compatibility_matrix.xml"; 614 const std::string kProductManifest = kProductVintfDir + "manifest.xml"; 615 const std::string kSystemExtManifest = kSystemExtVintfDir + "manifest.xml"; 616 617 const std::string kVendorManifestFragmentDir = kVendorVintfDir + "manifest/"; 618 const std::string kSystemManifestFragmentDir = kSystemVintfDir + "manifest/"; 619 const std::string kOdmManifestFragmentDir = kOdmVintfDir + "manifest/"; 620 const std::string kProductManifestFragmentDir = kProductVintfDir + "manifest/"; 621 const std::string kSystemExtManifestFragmentDir = kSystemExtVintfDir + "manifest/"; 622 623 const std::string kVendorLegacyManifest = "/vendor/manifest.xml"; 624 const std::string kVendorLegacyMatrix = "/vendor/compatibility_matrix.xml"; 625 const std::string kSystemLegacyManifest = "/system/manifest.xml"; 626 const std::string kSystemLegacyMatrix = "/system/compatibility_matrix.xml"; 627 const std::string kOdmLegacyVintfDir = "/odm/etc/"; 628 const std::string kOdmLegacyManifest = kOdmLegacyVintfDir + "manifest.xml"; 629 630 std::vector<std::string> dumpFileList() { 631 return { 632 // clang-format off 633 kSystemVintfDir, 634 kVendorVintfDir, 635 kOdmVintfDir, 636 kProductVintfDir, 637 kSystemExtVintfDir, 638 kOdmLegacyVintfDir, 639 kVendorLegacyManifest, 640 kVendorLegacyMatrix, 641 kSystemLegacyManifest, 642 kSystemLegacyMatrix, 643 // clang-format on 644 }; 645 } 646 647 } // namespace details 648 649 bool VintfObject::IsHalDeprecated(const MatrixHal& oldMatrixHal, 650 const CompatibilityMatrix& targetMatrix, 651 const ListInstances& listInstances, 652 const ChildrenMap& childrenMap, std::string* appendedError) { 653 bool isDeprecated = false; 654 oldMatrixHal.forEachInstance([&](const MatrixInstance& oldMatrixInstance) { 655 if (IsInstanceDeprecated(oldMatrixInstance, targetMatrix, listInstances, childrenMap, 656 appendedError)) { 657 isDeprecated = true; 658 } 659 return true; // continue to check next instance 660 }); 661 return isDeprecated; 662 } 663 664 // Let oldMatrixInstance = [email protected]::interface/instancePattern. 665 // If any "@servedVersion::interface/servedInstance" in listInstances([email protected]::interface) 666 // matches instancePattern, return true iff for all child interfaces (from 667 // GetListedInstanceInheritance), IsFqInstanceDeprecated returns false. 668 bool VintfObject::IsInstanceDeprecated(const MatrixInstance& oldMatrixInstance, 669 const CompatibilityMatrix& targetMatrix, 670 const ListInstances& listInstances, 671 const ChildrenMap& childrenMap, std::string* appendedError) { 672 const std::string& package = oldMatrixInstance.package(); 673 const Version& version = oldMatrixInstance.versionRange().minVer(); 674 const std::string& interface = oldMatrixInstance.interface(); 675 676 std::vector<std::string> instanceHint; 677 if (!oldMatrixInstance.isRegex()) { 678 instanceHint.push_back(oldMatrixInstance.exactInstance()); 679 } 680 681 std::vector<std::string> accumulatedErrors; 682 auto list = listInstances(package, version, interface, instanceHint); 683 684 for (const auto& pair : list) { 685 const std::string& servedInstance = pair.first; 686 Version servedVersion = pair.second; 687 std::string servedFqInstanceString = 688 toFQNameString(package, servedVersion, interface, servedInstance); 689 if (!oldMatrixInstance.matchInstance(servedInstance)) { 690 // ignore unrelated instance 691 continue; 692 } 693 694 auto inheritance = GetListedInstanceInheritance(package, servedVersion, interface, 695 servedInstance, listInstances, childrenMap); 696 if (!inheritance.has_value()) { 697 accumulatedErrors.push_back(inheritance.error().message()); 698 continue; 699 } 700 701 std::vector<std::string> errors; 702 for (const auto& fqInstance : *inheritance) { 703 auto result = IsFqInstanceDeprecated(targetMatrix, oldMatrixInstance.format(), 704 fqInstance, listInstances); 705 if (result.ok()) { 706 errors.clear(); 707 break; 708 } 709 errors.push_back(result.error().message()); 710 } 711 712 if (errors.empty()) { 713 continue; 714 } 715 accumulatedErrors.insert(accumulatedErrors.end(), errors.begin(), errors.end()); 716 } 717 718 if (accumulatedErrors.empty()) { 719 return false; 720 } 721 appendLine(appendedError, android::base::Join(accumulatedErrors, "\n")); 722 return true; 723 } 724 725 // Check if fqInstance is listed in |listInstances|. 726 bool VintfObject::IsInstanceListed(const ListInstances& listInstances, 727 const FqInstance& fqInstance) { 728 auto list = 729 listInstances(fqInstance.getPackage(), fqInstance.getVersion(), fqInstance.getInterface(), 730 {fqInstance.getInstance()} /* instanceHint*/); 731 return std::any_of(list.begin(), list.end(), 732 [&](const auto& pair) { return pair.first == fqInstance.getInstance(); }); 733 } 734 735 // Return a list of FqInstance, where each element: 736 // - is listed in |listInstances|; AND 737 // - is, or inherits from, package@version::interface/instance (as specified by |childrenMap|) 738 android::base::Result<std::vector<FqInstance>> VintfObject::GetListedInstanceInheritance( 739 const std::string& package, const Version& version, const std::string& interface, 740 const std::string& instance, const ListInstances& listInstances, 741 const ChildrenMap& childrenMap) { 742 FqInstance fqInstance; 743 if (!fqInstance.setTo(package, version.majorVer, version.minorVer, interface, instance)) { 744 return android::base::Error() << toFQNameString(package, version, interface, instance) 745 << " is not a valid FqInstance"; 746 } 747 748 if (!IsInstanceListed(listInstances, fqInstance)) { 749 return {}; 750 } 751 752 const FQName& fqName = fqInstance.getFqName(); 753 754 std::vector<FqInstance> ret; 755 ret.push_back(fqInstance); 756 757 auto childRange = childrenMap.equal_range(fqName.string()); 758 for (auto it = childRange.first; it != childRange.second; ++it) { 759 const auto& childFqNameString = it->second; 760 FQName childFqName; 761 if (!childFqName.setTo(childFqNameString)) { 762 return android::base::Error() << "Cannot parse " << childFqNameString << " as FQName"; 763 } 764 FqInstance childFqInstance; 765 if (!childFqInstance.setTo(childFqName, fqInstance.getInstance())) { 766 return android::base::Error() << "Cannot merge " << childFqName.string() << "/" 767 << fqInstance.getInstance() << " as FqInstance"; 768 continue; 769 } 770 if (!IsInstanceListed(listInstances, childFqInstance)) { 771 continue; 772 } 773 ret.push_back(childFqInstance); 774 } 775 return ret; 776 } 777 778 // Check if |fqInstance| is in |targetMatrix|; essentially equal to 779 // targetMatrix.matchInstance(fqInstance), but provides richer error message. In details: 780 // 1. package@x.?::interface/servedInstance is not in targetMatrix; OR 781 // 2. [email protected]::interface/servedInstance is in targetMatrix but 782 // servedInstance is not in listInstances([email protected]::interface) 783 android::base::Result<void> VintfObject::IsFqInstanceDeprecated( 784 const CompatibilityMatrix& targetMatrix, HalFormat format, const FqInstance& fqInstance, 785 const ListInstances& listInstances) { 786 // Find minimum package@x.? in target matrix, and check if instance is in target matrix. 787 bool foundInstance = false; 788 Version targetMatrixMinVer{SIZE_MAX, SIZE_MAX}; 789 targetMatrix.forEachInstanceOfPackage( 790 format, fqInstance.getPackage(), [&](const auto& targetMatrixInstance) { 791 if (targetMatrixInstance.versionRange().majorVer == fqInstance.getMajorVersion() && 792 targetMatrixInstance.interface() == fqInstance.getInterface() && 793 targetMatrixInstance.matchInstance(fqInstance.getInstance())) { 794 targetMatrixMinVer = 795 std::min(targetMatrixMinVer, targetMatrixInstance.versionRange().minVer()); 796 foundInstance = true; 797 } 798 return true; 799 }); 800 if (!foundInstance) { 801 return android::base::Error() 802 << fqInstance.string() << " is deprecated in compatibility matrix at FCM Version " 803 << targetMatrix.level() << "; it should not be served."; 804 } 805 806 // Assuming that targetMatrix requires @x.u-v, require that at least @x.u is served. 807 bool targetVersionServed = false; 808 for (const auto& newPair : 809 listInstances(fqInstance.getPackage(), targetMatrixMinVer, fqInstance.getInterface(), 810 {fqInstance.getInstance()} /* instanceHint */)) { 811 if (newPair.first == fqInstance.getInstance()) { 812 targetVersionServed = true; 813 break; 814 } 815 } 816 817 if (!targetVersionServed) { 818 return android::base::Error() 819 << fqInstance.string() << " is deprecated; requires at least " << targetMatrixMinVer; 820 } 821 return {}; 822 } 823 824 int32_t VintfObject::checkDeprecation(const ListInstances& listInstances, 825 const std::vector<HidlInterfaceMetadata>& hidlMetadata, 826 std::string* error) { 827 std::vector<Named<CompatibilityMatrix>> matrixFragments; 828 auto matrixFragmentsStatus = getAllFrameworkMatrixLevels(&matrixFragments, error); 829 if (matrixFragmentsStatus != OK) { 830 return matrixFragmentsStatus; 831 } 832 if (matrixFragments.empty()) { 833 if (error && error->empty()) { 834 *error = "Cannot get framework matrix for each FCM version for unknown error."; 835 } 836 return NAME_NOT_FOUND; 837 } 838 auto deviceManifest = getDeviceHalManifest(); 839 if (deviceManifest == nullptr) { 840 if (error) *error = "No device manifest."; 841 return NAME_NOT_FOUND; 842 } 843 Level deviceLevel = deviceManifest->level(); 844 if (deviceLevel == Level::UNSPECIFIED) { 845 if (error) *error = "Device manifest does not specify Shipping FCM Version."; 846 return BAD_VALUE; 847 } 848 849 const CompatibilityMatrix* targetMatrix = nullptr; 850 for (const auto& namedMatrix : matrixFragments) { 851 if (namedMatrix.object.level() == deviceLevel) { 852 targetMatrix = &namedMatrix.object; 853 } 854 } 855 if (targetMatrix == nullptr) { 856 if (error) 857 *error = "Cannot find framework matrix at FCM version " + to_string(deviceLevel) + "."; 858 return NAME_NOT_FOUND; 859 } 860 861 std::multimap<std::string, std::string> childrenMap; 862 for (const auto& child : hidlMetadata) { 863 for (const auto& parent : child.inherited) { 864 childrenMap.emplace(parent, child.name); 865 } 866 } 867 868 // Find a list of possibly deprecated HALs by comparing |listInstances| with older matrices. 869 // Matrices with unspecified level are considered "current". 870 bool isDeprecated = false; 871 for (const auto& namedMatrix : matrixFragments) { 872 if (namedMatrix.object.level() == Level::UNSPECIFIED) continue; 873 if (namedMatrix.object.level() >= deviceLevel) continue; 874 875 const auto& oldMatrix = namedMatrix.object; 876 for (const MatrixHal& hal : oldMatrix.getHals()) { 877 if (IsHalDeprecated(hal, *targetMatrix, listInstances, childrenMap, error)) { 878 isDeprecated = true; 879 } 880 } 881 } 882 883 return isDeprecated ? DEPRECATED : NO_DEPRECATED_HALS; 884 } 885 886 int32_t VintfObject::checkDeprecation(const std::vector<HidlInterfaceMetadata>& hidlMetadata, 887 std::string* error) { 888 using namespace std::placeholders; 889 auto deviceManifest = getDeviceHalManifest(); 890 ListInstances inManifest = 891 [&deviceManifest](const std::string& package, Version version, const std::string& interface, 892 const std::vector<std::string>& /* hintInstances */) { 893 std::vector<std::pair<std::string, Version>> ret; 894 deviceManifest->forEachInstanceOfInterface( 895 HalFormat::HIDL, package, version, interface, 896 [&ret](const ManifestInstance& manifestInstance) { 897 ret.push_back( 898 std::make_pair(manifestInstance.instance(), manifestInstance.version())); 899 return true; 900 }); 901 return ret; 902 }; 903 return checkDeprecation(inManifest, hidlMetadata, error); 904 } 905 906 Level VintfObject::getKernelLevel(std::string* error) { 907 auto manifest = getDeviceHalManifest(); 908 if (!manifest) { 909 if (error) *error = "Cannot retrieve device manifest."; 910 return Level::UNSPECIFIED; 911 } 912 if (manifest->kernel().has_value() && manifest->kernel()->level() != Level::UNSPECIFIED) { 913 return manifest->kernel()->level(); 914 } 915 if (error) *error = "Device manifest does not specify kernel FCM version."; 916 return Level::UNSPECIFIED; 917 } 918 919 const std::unique_ptr<FileSystem>& VintfObject::getFileSystem() { 920 return mFileSystem; 921 } 922 923 const std::unique_ptr<PropertyFetcher>& VintfObject::getPropertyFetcher() { 924 return mPropertyFetcher; 925 } 926 927 const std::unique_ptr<ObjectFactory<RuntimeInfo>>& VintfObject::getRuntimeInfoFactory() { 928 return mRuntimeInfoFactory; 929 } 930 931 android::base::Result<bool> VintfObject::hasFrameworkCompatibilityMatrixExtensions() { 932 std::vector<Named<CompatibilityMatrix>> matrixFragments; 933 std::string error; 934 status_t status = getAllFrameworkMatrixLevels(&matrixFragments, &error); 935 if (status != OK) { 936 return android::base::Error(-status) 937 << "Cannot get all framework matrix fragments: " << error; 938 } 939 for (const auto& namedMatrix : matrixFragments) { 940 // Returns true if product matrix exists. 941 if (android::base::StartsWith(namedMatrix.name, kProductVintfDir)) { 942 return true; 943 } 944 // Returns true if system_ext matrix exists. 945 if (android::base::StartsWith(namedMatrix.name, kSystemExtVintfDir)) { 946 return true; 947 } 948 // Returns true if device system matrix exists. 949 if (android::base::StartsWith(namedMatrix.name, kSystemVintfDir) && 950 namedMatrix.object.level() == Level::UNSPECIFIED && 951 !namedMatrix.object.getHals().empty()) { 952 return true; 953 } 954 } 955 return false; 956 } 957 958 android::base::Result<void> VintfObject::checkUnusedHals( 959 const std::vector<HidlInterfaceMetadata>& hidlMetadata) { 960 auto matrix = getFrameworkCompatibilityMatrix(); 961 if (matrix == nullptr) { 962 return android::base::Error(-NAME_NOT_FOUND) << "Missing framework matrix."; 963 } 964 auto manifest = getDeviceHalManifest(); 965 if (manifest == nullptr) { 966 return android::base::Error(-NAME_NOT_FOUND) << "Missing device manifest."; 967 } 968 auto unused = manifest->checkUnusedHals(*matrix, hidlMetadata); 969 if (!unused.empty()) { 970 return android::base::Error() 971 << "The following instances are in the device manifest but " 972 << "not specified in framework compatibility matrix: \n" 973 << " " << android::base::Join(unused, "\n ") << "\n" 974 << "Suggested fix:\n" 975 << "1. Update deprecated HALs to the latest version.\n" 976 << "2. Check for any typos in device manifest or framework compatibility " 977 << "matrices with FCM version >= " << matrix->level() << ".\n" 978 << "3. For new platform HALs, add them to any framework compatibility matrix " 979 << "with FCM version >= " << matrix->level() << " where applicable.\n" 980 << "4. For device-specific HALs, add to DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE " 981 << "or DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE."; 982 } 983 return {}; 984 } 985 986 // make_unique does not work because VintfObject constructor is private. 987 VintfObject::Builder::Builder() : mObject(std::unique_ptr<VintfObject>(new VintfObject())) {} 988 989 VintfObject::Builder& VintfObject::Builder::setFileSystem(std::unique_ptr<FileSystem>&& e) { 990 mObject->mFileSystem = std::move(e); 991 return *this; 992 } 993 994 VintfObject::Builder& VintfObject::Builder::setRuntimeInfoFactory( 995 std::unique_ptr<ObjectFactory<RuntimeInfo>>&& e) { 996 mObject->mRuntimeInfoFactory = std::move(e); 997 return *this; 998 } 999 1000 VintfObject::Builder& VintfObject::Builder::setPropertyFetcher( 1001 std::unique_ptr<PropertyFetcher>&& e) { 1002 mObject->mPropertyFetcher = std::move(e); 1003 return *this; 1004 } 1005 1006 std::unique_ptr<VintfObject> VintfObject::Builder::build() { 1007 if (!mObject->mFileSystem) mObject->mFileSystem = createDefaultFileSystem(); 1008 if (!mObject->mRuntimeInfoFactory) 1009 mObject->mRuntimeInfoFactory = std::make_unique<ObjectFactory<RuntimeInfo>>(); 1010 if (!mObject->mPropertyFetcher) mObject->mPropertyFetcher = createDefaultPropertyFetcher(); 1011 return std::move(mObject); 1012 } 1013 1014 } // namespace vintf 1015 } // namespace android 1016