Home | History | Annotate | Download | only in hidl
      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 &currentFQName : 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