1 /* 2 * Copyright (C) 2016 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 "Coordinator.h" 18 19 #include <dirent.h> 20 #include <sys/stat.h> 21 22 #include <algorithm> 23 #include <iterator> 24 25 #include <android-base/logging.h> 26 #include <hidl-hash/Hash.h> 27 #include <hidl-util/StringHelper.h> 28 #include <iostream> 29 30 #include "AST.h" 31 #include "Interface.h" 32 #include "hidl-gen_l.h" 33 34 static bool existdir(const char *name) { 35 DIR *dir = opendir(name); 36 if (dir == NULL) { 37 return false; 38 } 39 closedir(dir); 40 return true; 41 } 42 43 namespace android { 44 45 const std::string &Coordinator::getRootPath() const { 46 return mRootPath; 47 } 48 49 void Coordinator::setRootPath(const std::string &rootPath) { 50 mRootPath = rootPath; 51 52 if (!mRootPath.empty() && !StringHelper::EndsWith(mRootPath, "/")) { 53 mRootPath += "/"; 54 } 55 } 56 57 void Coordinator::setOutputPath(const std::string& outputPath) { 58 mOutputPath = outputPath; 59 } 60 61 void Coordinator::setVerbose(bool verbose) { 62 mVerbose = verbose; 63 } 64 65 bool Coordinator::isVerbose() const { 66 return mVerbose; 67 } 68 69 void Coordinator::setDepFile(const std::string& depFile) { 70 mDepFile = depFile; 71 } 72 73 const std::string& Coordinator::getOwner() const { 74 return mOwner; 75 } 76 void Coordinator::setOwner(const std::string& owner) { 77 mOwner = owner; 78 } 79 80 status_t Coordinator::addPackagePath(const std::string& root, const std::string& path, std::string* error) { 81 FQName package = FQName(root, "0.0", ""); 82 for (const PackageRoot &packageRoot : mPackageRoots) { 83 if (packageRoot.root.inPackage(root) || package.inPackage(packageRoot.root.package())) { 84 if (error != nullptr) { 85 *error = "ERROR: conflicting package roots " + 86 packageRoot.root.package() + 87 " and " + 88 root; 89 } 90 91 return UNKNOWN_ERROR; 92 } 93 } 94 95 mPackageRoots.push_back({path, package}); 96 return OK; 97 } 98 void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) { 99 addPackagePath(root, path, nullptr /* error */); 100 } 101 102 Formatter Coordinator::getFormatter(const FQName& fqName, Location location, 103 const std::string& fileName) const { 104 if (location == Location::STANDARD_OUT) { 105 return Formatter(stdout); 106 } 107 108 std::string filepath; 109 status_t err = getFilepath(fqName, location, fileName, &filepath); 110 if (err != OK) { 111 return Formatter::invalid(); 112 } 113 114 onFileAccess(filepath, "w"); 115 116 if (!Coordinator::MakeParentHierarchy(filepath)) { 117 fprintf(stderr, "ERROR: could not make directories for %s.\n", filepath.c_str()); 118 return Formatter::invalid(); 119 } 120 121 FILE* file = fopen(filepath.c_str(), "w"); 122 123 if (file == nullptr) { 124 fprintf(stderr, "ERROR: could not open file %s: %d\n", filepath.c_str(), errno); 125 return Formatter::invalid(); 126 } 127 128 return Formatter(file); 129 } 130 131 status_t Coordinator::getFilepath(const FQName& fqName, Location location, 132 const std::string& fileName, std::string* path) const { 133 status_t err; 134 std::string packagePath; 135 std::string packageRootPath; 136 137 switch (location) { 138 case Location::DIRECT: { /* nothing */ 139 *path = mOutputPath + fileName; 140 } break; 141 case Location::PACKAGE_ROOT: { 142 err = getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath); 143 if (err != OK) return err; 144 145 *path = mOutputPath + packagePath + fileName; 146 } break; 147 case Location::GEN_OUTPUT: { 148 err = convertPackageRootToPath(fqName, &packageRootPath); 149 if (err != OK) return err; 150 err = getPackagePath(fqName, true /* relative */, false /* sanitized */, &packagePath); 151 if (err != OK) return err; 152 153 *path = mOutputPath + packageRootPath + packagePath + fileName; 154 } break; 155 case Location::GEN_SANITIZED: { 156 err = convertPackageRootToPath(fqName, &packageRootPath); 157 if (err != OK) return err; 158 err = getPackagePath(fqName, true /* relative */, true /* sanitized */, &packagePath); 159 if (err != OK) return err; 160 161 *path = mOutputPath + packageRootPath + packagePath + fileName; 162 } break; 163 default: { CHECK(false) << "Invalid location: " << static_cast<size_t>(location); } 164 } 165 166 return OK; 167 } 168 169 void Coordinator::onFileAccess(const std::string& path, const std::string& mode) const { 170 if (mode == "r") { 171 // This is a global list. It's not cleared when a second fqname is processed for 172 // two reasons: 173 // 1). If there is a bug in hidl-gen, the dependencies on the first project from 174 // the second would be required to recover correctly when the bug is fixed. 175 // 2). This option is never used in Android builds. 176 mReadFiles.insert(StringHelper::LTrim(path, mRootPath)); 177 } 178 179 if (!mVerbose) { 180 return; 181 } 182 183 fprintf(stderr, 184 "VERBOSE: file access %s %s\n", path.c_str(), mode.c_str()); 185 } 186 187 status_t Coordinator::writeDepFile(const std::string& forFile) const { 188 // No dep file requested 189 if (mDepFile.empty()) return OK; 190 191 onFileAccess(mDepFile, "w"); 192 193 FILE* file = fopen(mDepFile.c_str(), "w"); 194 if (file == nullptr) { 195 fprintf(stderr, "ERROR: could not open dep file at %s.\n", mDepFile.c_str()); 196 return UNKNOWN_ERROR; 197 } 198 199 Formatter out(file, 2 /* spacesPerIndent */); 200 out << StringHelper::LTrim(forFile, mOutputPath) << ": \\\n"; 201 out.indent([&] { 202 for (const std::string& file : mReadFiles) { 203 out << StringHelper::LTrim(file, mRootPath) << " \\\n"; 204 } 205 }); 206 return OK; 207 } 208 209 AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs, 210 Enforce enforcement) const { 211 AST* ret; 212 status_t err = parseOptional(fqName, &ret, parsedASTs, enforcement); 213 if (err != OK) CHECK(ret == nullptr); // internal consistency 214 215 // only in a handful of places do we want to distinguish between 216 // a missing file and a bad AST. Everywhere else, we just want to 217 // throw an error if we expect an AST to be present but it is not. 218 return ret; 219 } 220 221 status_t Coordinator::parseOptional(const FQName& fqName, AST** ast, std::set<AST*>* parsedASTs, 222 Enforce enforcement) const { 223 CHECK(fqName.isFullyQualified()); 224 225 auto it = mCache.find(fqName); 226 if (it != mCache.end()) { 227 *ast = (*it).second; 228 229 if (*ast != nullptr && parsedASTs != nullptr) { 230 parsedASTs->insert(*ast); 231 } 232 233 if (*ast == nullptr) { 234 // circular import OR that AST has errors in it 235 return UNKNOWN_ERROR; 236 } 237 238 return OK; 239 } 240 241 // Add this to the cache immediately, so we can discover circular imports. 242 mCache[fqName] = nullptr; 243 244 AST *typesAST = nullptr; 245 246 if (fqName.name() != "types") { 247 // Any interface file implicitly imports its package's types.hal. 248 FQName typesName = fqName.getTypesForPackage(); 249 // Do not enforce on imports. Do not add imports' imports to this AST. 250 status_t err = parseOptional(typesName, &typesAST, nullptr, Enforce::NONE); 251 if (err != OK) return err; 252 253 // fall through. 254 } 255 256 std::string packagePath; 257 status_t err = 258 getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath); 259 if (err != OK) return err; 260 261 const std::string path = makeAbsolute(packagePath + fqName.name() + ".hal"); 262 263 *ast = new AST(this, &Hash::getHash(path)); 264 265 if (typesAST != NULL) { 266 // If types.hal for this AST's package existed, make it's defined 267 // types available to the (about to be parsed) AST right away. 268 (*ast)->addImportedAST(typesAST); 269 } 270 271 std::unique_ptr<FILE, std::function<void(FILE*)>> file(fopen(path.c_str(), "rb"), fclose); 272 273 if (file == nullptr) { 274 mCache.erase(fqName); // nullptr in cache is used to find circular imports 275 delete *ast; 276 *ast = nullptr; 277 return OK; // File does not exist, nullptr AST* == file doesn't exist. 278 } 279 280 onFileAccess(path, "r"); 281 282 // parse file takes ownership of file 283 if (parseFile(*ast, std::move(file)) != OK || (*ast)->postParse() != OK) { 284 delete *ast; 285 *ast = nullptr; 286 return UNKNOWN_ERROR; 287 } 288 289 if ((*ast)->package().package() != fqName.package() || 290 (*ast)->package().version() != fqName.version()) { 291 fprintf(stderr, 292 "ERROR: File at '%s' does not match expected package and/or " 293 "version.\n", 294 path.c_str()); 295 296 err = UNKNOWN_ERROR; 297 } else { 298 if ((*ast)->isInterface()) { 299 if (fqName.name() == "types") { 300 fprintf(stderr, 301 "ERROR: File at '%s' declares an interface '%s' " 302 "instead of the expected types common to the package.\n", 303 path.c_str(), (*ast)->getInterface()->localName().c_str()); 304 305 err = UNKNOWN_ERROR; 306 } else if ((*ast)->getInterface()->localName() != fqName.name()) { 307 fprintf(stderr, 308 "ERROR: File at '%s' does not declare interface type " 309 "'%s'.\n", 310 path.c_str(), 311 fqName.name().c_str()); 312 313 err = UNKNOWN_ERROR; 314 } 315 } else if (fqName.name() != "types") { 316 fprintf(stderr, 317 "ERROR: File at '%s' declares types rather than the " 318 "expected interface type '%s'.\n", 319 path.c_str(), 320 fqName.name().c_str()); 321 322 err = UNKNOWN_ERROR; 323 } else if ((*ast)->containsInterfaces()) { 324 fprintf(stderr, 325 "ERROR: types.hal file at '%s' declares at least one " 326 "interface type.\n", 327 path.c_str()); 328 329 err = UNKNOWN_ERROR; 330 } 331 } 332 333 if (err != OK) { 334 delete *ast; 335 *ast = nullptr; 336 return err; 337 } 338 339 if (parsedASTs != nullptr) { 340 parsedASTs->insert(*ast); 341 } 342 343 // put it into the cache now, so that enforceRestrictionsOnPackage can 344 // parse fqName. 345 mCache[fqName] = *ast; 346 347 // For each .hal file that hidl-gen parses, the whole package will be checked. 348 err = enforceRestrictionsOnPackage(fqName, enforcement); 349 if (err != OK) { 350 mCache[fqName] = nullptr; 351 delete *ast; 352 *ast = nullptr; 353 return err; 354 } 355 356 return OK; 357 } 358 359 const Coordinator::PackageRoot* Coordinator::findPackageRoot(const FQName& fqName) const { 360 CHECK(!fqName.package().empty()); 361 362 // Find the right package prefix and path for this FQName. For 363 // example, if FQName is "android.hardware.nfc (at) 1.0::INfc", and the 364 // prefix:root is set to [ "android.hardware:hardware/interfaces", 365 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the 366 // prefix "android.hardware" and the package root 367 // "hardware/interfaces". 368 369 auto ret = mPackageRoots.end(); 370 for (auto it = mPackageRoots.begin(); it != mPackageRoots.end(); it++) { 371 if (!fqName.inPackage(it->root.package())) { 372 continue; 373 } 374 375 if (ret != mPackageRoots.end()) { 376 std::cerr << "ERROR: Multiple package roots found for " << fqName.string() << " (" 377 << it->root.package() << " and " << ret->root.package() << ")\n"; 378 return nullptr; 379 } 380 381 ret = it; 382 } 383 384 if (ret == mPackageRoots.end()) { 385 std::cerr << "ERROR: Package root not specified for " << fqName.string() << "\n"; 386 return nullptr; 387 } 388 389 return &(*ret); 390 } 391 392 std::string Coordinator::makeAbsolute(const std::string& path) const { 393 if (StringHelper::StartsWith(path, "/") || mRootPath.empty()) { 394 return path; 395 } 396 397 return mRootPath + path; 398 } 399 400 status_t Coordinator::getPackageRoot(const FQName& fqName, std::string* root) const { 401 const PackageRoot* packageRoot = findPackageRoot(fqName); 402 if (root == nullptr) { 403 return UNKNOWN_ERROR; 404 } 405 *root = packageRoot->root.package(); 406 return OK; 407 } 408 409 status_t Coordinator::getPackageRootPath(const FQName& fqName, std::string* path) const { 410 const PackageRoot* packageRoot = findPackageRoot(fqName); 411 if (packageRoot == nullptr) { 412 return UNKNOWN_ERROR; 413 } 414 *path = packageRoot->path; 415 return OK; 416 } 417 418 status_t Coordinator::getPackagePath(const FQName& fqName, bool relative, bool sanitized, 419 std::string* path) const { 420 const PackageRoot* packageRoot = findPackageRoot(fqName); 421 if (packageRoot == nullptr) return UNKNOWN_ERROR; 422 423 // Given FQName of "android.hardware.nfc.test (at) 1.0::IFoo" and a prefix 424 // "android.hardware", the suffix is "nfc.test". 425 std::string suffix = StringHelper::LTrim(fqName.package(), packageRoot->root.package()); 426 suffix = StringHelper::LTrim(suffix, "."); 427 428 std::vector<std::string> suffixComponents; 429 StringHelper::SplitString(suffix, '.', &suffixComponents); 430 431 std::vector<std::string> components; 432 if (!relative) { 433 components.push_back(StringHelper::RTrimAll(packageRoot->path, "/")); 434 } 435 components.insert(components.end(), suffixComponents.begin(), suffixComponents.end()); 436 components.push_back(sanitized ? fqName.sanitizedVersion() : fqName.version()); 437 438 *path = StringHelper::JoinStrings(components, "/") + "/"; 439 return OK; 440 } 441 442 status_t Coordinator::getPackageInterfaceFiles( 443 const FQName &package, 444 std::vector<std::string> *fileNames) const { 445 fileNames->clear(); 446 447 std::string packagePath; 448 status_t err = 449 getPackagePath(package, false /* relative */, false /* sanitized */, &packagePath); 450 if (err != OK) return err; 451 452 const std::string path = makeAbsolute(packagePath); 453 DIR* dir = opendir(path.c_str()); 454 455 if (dir == NULL) { 456 fprintf(stderr, "ERROR: Could not open package path %s for package %s:\n%s\n", 457 packagePath.c_str(), package.string().c_str(), path.c_str()); 458 return -errno; 459 } 460 461 struct dirent *ent; 462 while ((ent = readdir(dir)) != NULL) { 463 if (ent->d_type != DT_REG) { 464 continue; 465 } 466 467 const auto suffix = ".hal"; 468 const auto suffix_len = std::strlen(suffix); 469 const auto d_namelen = strlen(ent->d_name); 470 471 if (d_namelen < suffix_len 472 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) { 473 continue; 474 } 475 476 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len)); 477 } 478 479 closedir(dir); 480 dir = NULL; 481 482 std::sort(fileNames->begin(), fileNames->end(), 483 [](const std::string& lhs, const std::string& rhs) -> bool { 484 if (lhs == "types") { 485 return true; 486 } 487 if (rhs == "types") { 488 return false; 489 } 490 return lhs < rhs; 491 }); 492 493 return OK; 494 } 495 496 status_t Coordinator::appendPackageInterfacesToVector( 497 const FQName &package, 498 std::vector<FQName> *packageInterfaces) const { 499 packageInterfaces->clear(); 500 501 std::vector<std::string> fileNames; 502 status_t err = getPackageInterfaceFiles(package, &fileNames); 503 504 if (err != OK) { 505 return err; 506 } 507 508 for (const auto &fileName : fileNames) { 509 FQName subFQName(package.package(), package.version(), fileName); 510 packageInterfaces->push_back(subFQName); 511 } 512 513 return OK; 514 } 515 516 status_t Coordinator::convertPackageRootToPath(const FQName& fqName, std::string* path) const { 517 std::string packageRoot; 518 status_t err = getPackageRoot(fqName, &packageRoot); 519 if (err != OK) return err; 520 521 if (*(packageRoot.end()--) != '.') { 522 packageRoot += '.'; 523 } 524 525 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/'); 526 527 *path = packageRoot; // now converted to a path 528 return OK; 529 } 530 531 status_t Coordinator::isTypesOnlyPackage(const FQName& package, bool* result) const { 532 std::vector<FQName> packageInterfaces; 533 534 status_t err = appendPackageInterfacesToVector(package, &packageInterfaces); 535 536 if (err != OK) { 537 *result = false; 538 return err; 539 } 540 541 *result = packageInterfaces.size() == 1 && packageInterfaces[0].name() == "types"; 542 return OK; 543 } 544 545 status_t Coordinator::addUnreferencedTypes(const std::vector<FQName>& packageInterfaces, 546 std::set<FQName>* unreferencedDefinitions, 547 std::set<FQName>* unreferencedImports) const { 548 CHECK(unreferencedDefinitions != nullptr); 549 CHECK(unreferencedImports != nullptr); 550 551 std::set<FQName> packageDefinedTypes; 552 std::set<FQName> packageReferencedTypes; 553 std::set<FQName> packageImportedTypes; 554 std::set<FQName> typesDefinedTypes; // only types.hal types 555 556 for (const auto& fqName : packageInterfaces) { 557 AST* ast = parse(fqName); 558 if (!ast) { 559 std::cerr << "ERROR: Could not parse " << fqName.string() << ". Aborting." << std::endl; 560 561 return UNKNOWN_ERROR; 562 } 563 564 ast->addDefinedTypes(&packageDefinedTypes); 565 ast->addReferencedTypes(&packageReferencedTypes); 566 ast->getAllImportedNamesGranular(&packageImportedTypes); 567 568 if (fqName.name() == "types") { 569 ast->addDefinedTypes(&typesDefinedTypes); 570 } 571 } 572 573 #if 0 574 for (const auto &fqName : packageDefinedTypes) { 575 std::cout << "VERBOSE: DEFINED " << fqName.string() << std::endl; 576 } 577 578 for (const auto &fqName : packageImportedTypes) { 579 std::cout << "VERBOSE: IMPORTED " << fqName.string() << std::endl; 580 } 581 582 for (const auto &fqName : packageReferencedTypes) { 583 std::cout << "VERBOSE: REFERENCED " << fqName.string() << std::endl; 584 } 585 586 for (const auto &fqName : typesDefinedTypes) { 587 std::cout << "VERBOSE: DEFINED in types.hal " << fqName.string() << std::endl; 588 } 589 #endif 590 591 for (const auto& fqName : packageReferencedTypes) { 592 packageDefinedTypes.erase(fqName); 593 packageImportedTypes.erase(fqName); 594 } 595 596 // A package implicitly imports its own types.hal, only track them in one set. 597 for (const auto& fqName : typesDefinedTypes) { 598 packageImportedTypes.erase(fqName); 599 } 600 601 // defined but not referenced 602 unreferencedDefinitions->insert(packageDefinedTypes.begin(), packageDefinedTypes.end()); 603 // imported but not referenced 604 unreferencedImports->insert(packageImportedTypes.begin(), packageImportedTypes.end()); 605 return OK; 606 } 607 608 status_t Coordinator::enforceRestrictionsOnPackage(const FQName& fqName, 609 Enforce enforcement) const { 610 CHECK(enforcement == Enforce::FULL || enforcement == Enforce::NO_HASH || 611 enforcement == Enforce::NONE); 612 613 // need fqName to be something like android.hardware.foo (at) 1.0. 614 // name and valueName is ignored. 615 if (fqName.package().empty() || fqName.version().empty()) { 616 std::cerr << "ERROR: Cannot enforce restrictions on package " << fqName.string() 617 << ": package or version is missing." << std::endl; 618 return BAD_VALUE; 619 } 620 621 if (enforcement == Enforce::NONE) { 622 return OK; 623 } 624 625 FQName package = fqName.getPackageAndVersion(); 626 // look up cache. 627 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) { 628 return OK; 629 } 630 631 // enforce all rules. 632 status_t err; 633 634 err = enforceMinorVersionUprevs(package, enforcement); 635 if (err != OK) { 636 return err; 637 } 638 639 if (enforcement != Enforce::NO_HASH) { 640 err = enforceHashes(package); 641 if (err != OK) { 642 return err; 643 } 644 } 645 646 // cache it so that it won't need to be enforced again. 647 mPackagesEnforced.insert(package); 648 return OK; 649 } 650 651 status_t Coordinator::enforceMinorVersionUprevs(const FQName& currentPackage, 652 Enforce enforcement) const { 653 if(!currentPackage.hasVersion()) { 654 std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string() 655 << ": missing version." << std::endl; 656 return UNKNOWN_ERROR; 657 } 658 659 if (currentPackage.getPackageMinorVersion() == 0) { 660 return OK; // ignore for @x.0 661 } 662 663 bool hasPrevPackage = false; 664 FQName prevPackage = currentPackage; 665 while (prevPackage.getPackageMinorVersion() > 0) { 666 prevPackage = prevPackage.downRev(); 667 668 std::string prevPackagePath; 669 status_t err = getPackagePath(prevPackage, false /* relative */, false /* sanitized */, 670 &prevPackagePath); 671 if (err != OK) return err; 672 673 if (existdir(makeAbsolute(prevPackagePath).c_str())) { 674 hasPrevPackage = true; 675 break; 676 } 677 } 678 if (!hasPrevPackage) { 679 // no @x.z, where z < y, exist. 680 return OK; 681 } 682 683 if (prevPackage != currentPackage.downRev()) { 684 std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string() 685 << ": Found package " << prevPackage.string() << " but missing " 686 << currentPackage.downRev().string() << "; you cannot skip a minor version." 687 << std::endl; 688 return UNKNOWN_ERROR; 689 } 690 691 bool prevIsTypesOnly; 692 status_t err = isTypesOnlyPackage(prevPackage, &prevIsTypesOnly); 693 if (err != OK) return err; 694 695 if (prevIsTypesOnly) { 696 // A types only package can be extended in any way. 697 return OK; 698 } 699 700 std::vector<FQName> packageInterfaces; 701 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces); 702 if (err != OK) { 703 return err; 704 } 705 706 bool extendedInterface = false; 707 for (const FQName ¤tFQName : packageInterfaces) { 708 if (currentFQName.name() == "types") { 709 continue; // ignore types.hal 710 } 711 712 const Interface *iface = nullptr; 713 AST* currentAST = parse(currentFQName, nullptr /* parsedASTs */, enforcement); 714 if (currentAST != nullptr) { 715 iface = currentAST->getInterface(); 716 } 717 if (iface == nullptr) { 718 if (currentAST == nullptr) { 719 std::cerr << "WARNING: Skipping " << currentFQName.string() 720 << " because it could not be found or parsed" 721 << " or " << currentPackage.string() << " doesn't pass all requirements." 722 << std::endl; 723 } else { 724 std::cerr << "WARNING: Skipping " << currentFQName.string() 725 << " because the file might contain more than one interface." 726 << std::endl; 727 } 728 continue; 729 } 730 731 if (iface->superType() == nullptr) { 732 CHECK(iface->isIBase()); 733 continue; 734 } 735 736 // Assume that currentFQName == android.hardware.foo (at) 2.2::IFoo. 737 FQName lastFQName(prevPackage.package(), prevPackage.version(), 738 currentFQName.name()); 739 AST *lastAST = parse(lastFQName); 740 741 for (; lastFQName.getPackageMinorVersion() > 0 && 742 (lastAST == nullptr || lastAST->getInterface() == nullptr) 743 ; lastFQName = lastFQName.downRev(), lastAST = parse(lastFQName)) { 744 // nothing 745 } 746 747 // Then lastFQName == android.hardware.foo (at) 2.1::IFoo or 748 // lastFQName == android.hardware.foo (at) 2.0::IFoo if 2.1 doesn't exist. 749 750 bool lastFQNameExists = lastAST != nullptr && lastAST->getInterface() != nullptr; 751 752 if (!lastFQNameExists) { 753 continue; 754 } 755 756 if (iface->superType()->fqName() != lastFQName) { 757 std::cerr << "ERROR: Cannot enforce minor version uprevs for " 758 << currentPackage.string() << ": " << iface->fqName().string() << " extends " 759 << iface->superType()->fqName().string() 760 << ", which is not allowed. It must extend " << lastFQName.string() 761 << std::endl; 762 return UNKNOWN_ERROR; 763 } 764 765 // at least one interface must extend the previous version 766 // @2.0::IFoo does not work. It must be @2.1::IFoo for at least one interface. 767 if (lastFQName.getPackageAndVersion() == prevPackage.getPackageAndVersion()) { 768 extendedInterface = true; 769 } 770 771 if (mVerbose) { 772 std::cout << "VERBOSE: EnforceMinorVersionUprevs: " << currentFQName.string() 773 << " passes." << std::endl; 774 } 775 } 776 777 if (!extendedInterface) { 778 // No interface extends the interface with the same name in @x.(y-1). 779 std::cerr << "ERROR: " << currentPackage.string() 780 << " doesn't pass minor version uprev requirement. " 781 << "Requires at least one interface to extend an interface with the same name " 782 << "from " << prevPackage.string() << "." << std::endl; 783 return UNKNOWN_ERROR; 784 } 785 786 return OK; 787 } 788 789 Coordinator::HashStatus Coordinator::checkHash(const FQName& fqName) const { 790 AST* ast = parse(fqName); 791 if (ast == nullptr) return HashStatus::ERROR; 792 793 std::string rootPath; 794 status_t err = getPackageRootPath(fqName, &rootPath); 795 if (err != OK) return HashStatus::ERROR; 796 797 std::string hashPath = makeAbsolute(rootPath) + "/current.txt"; 798 std::string error; 799 bool fileExists; 800 std::vector<std::string> frozen = 801 Hash::lookupHash(hashPath, fqName.string(), &error, &fileExists); 802 if (fileExists) onFileAccess(hashPath, "r"); 803 804 if (error.size() > 0) { 805 std::cerr << "ERROR: " << error << std::endl; 806 return HashStatus::ERROR; 807 } 808 809 // hash not defined, interface not frozen 810 if (frozen.size() == 0) { 811 // This ensures that it can be detected. 812 Hash::clearHash(ast->getFilename()); 813 814 return HashStatus::UNFROZEN; 815 } 816 817 std::string currentHash = ast->getFileHash()->hexString(); 818 819 if (std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) { 820 std::cerr << "ERROR: " << fqName.string() << " has hash " << currentHash 821 << " which does not match hash on record. This interface has " 822 << "been frozen. Do not change it!" << std::endl; 823 return HashStatus::CHANGED; 824 } 825 826 return HashStatus::FROZEN; 827 } 828 829 status_t Coordinator::getUnfrozenDependencies(const FQName& fqName, 830 std::set<FQName>* result) const { 831 CHECK(result != nullptr); 832 833 AST* ast = parse(fqName); 834 if (ast == nullptr) return UNKNOWN_ERROR; 835 836 std::set<FQName> imported; 837 ast->getImportedPackages(&imported); 838 839 // no circular dependency is already guaranteed by parsing 840 // indirect dependencies will be checked when the imported interface frozen checks are done 841 for (const FQName& importedPackage : imported) { 842 std::vector<FQName> packageInterfaces; 843 status_t err = appendPackageInterfacesToVector(importedPackage, &packageInterfaces); 844 if (err != OK) { 845 return err; 846 } 847 848 for (const FQName& importedName : packageInterfaces) { 849 HashStatus status = checkHash(importedName); 850 if (status == HashStatus::ERROR) return UNKNOWN_ERROR; 851 if (status == HashStatus::UNFROZEN) { 852 result->insert(importedName); 853 } 854 } 855 } 856 857 return OK; 858 } 859 860 status_t Coordinator::enforceHashes(const FQName& currentPackage) const { 861 std::vector<FQName> packageInterfaces; 862 status_t err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces); 863 if (err != OK) { 864 return err; 865 } 866 867 for (const FQName& currentFQName : packageInterfaces) { 868 HashStatus status = checkHash(currentFQName); 869 870 if (status == HashStatus::ERROR) return UNKNOWN_ERROR; 871 if (status == HashStatus::CHANGED) return UNKNOWN_ERROR; 872 873 // frozen interface can only depend on a frozen interface 874 if (status == HashStatus::FROZEN) { 875 std::set<FQName> unfrozenDependencies; 876 err = getUnfrozenDependencies(currentFQName, &unfrozenDependencies); 877 if (err != OK) return err; 878 879 if (!unfrozenDependencies.empty()) { 880 std::cerr << "ERROR: Frozen interface " << currentFQName.string() 881 << " cannot depend on unfrozen thing(s):" << std::endl; 882 for (const FQName& name : unfrozenDependencies) { 883 std::cerr << " (unfrozen) " << name.string() << std::endl; 884 } 885 return UNKNOWN_ERROR; 886 } 887 } 888 889 // UNFROZEN, ignore 890 } 891 892 return err; 893 } 894 895 bool Coordinator::MakeParentHierarchy(const std::string &path) { 896 static const mode_t kMode = 0755; 897 898 size_t start = 1; // Ignore leading '/' 899 size_t slashPos; 900 while ((slashPos = path.find('/', start)) != std::string::npos) { 901 std::string partial = path.substr(0, slashPos); 902 903 struct stat st; 904 if (stat(partial.c_str(), &st) < 0) { 905 if (errno != ENOENT) { 906 return false; 907 } 908 909 int res = mkdir(partial.c_str(), kMode); 910 if (res < 0) { 911 return false; 912 } 913 } else if (!S_ISDIR(st.st_mode)) { 914 return false; 915 } 916 917 start = slashPos + 1; 918 } 919 920 return true; 921 } 922 923 } // namespace android 924 925