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 "AST.h"
     18 #include "Coordinator.h"
     19 #include "Scope.h"
     20 
     21 #include <android-base/logging.h>
     22 #include <hidl-hash/Hash.h>
     23 #include <hidl-util/FQName.h>
     24 #include <hidl-util/Formatter.h>
     25 #include <hidl-util/StringHelper.h>
     26 #include <stdio.h>
     27 #include <sys/stat.h>
     28 #include <unistd.h>
     29 #include <iostream>
     30 #include <set>
     31 #include <string>
     32 #include <vector>
     33 
     34 using namespace android;
     35 
     36 enum class OutputMode {
     37     NEEDS_DIR,   // -o output option expects a directory
     38     NEEDS_FILE,  // -o output option expects a file
     39     NEEDS_SRC,   // for changes inside the source tree itself
     40     NOT_NEEDED   // does not create files
     41 };
     42 
     43 enum class GenerationGranularity {
     44     PER_PACKAGE,  // Files generated for each package
     45     PER_FILE,     // Files generated for each hal file
     46     PER_TYPE,     // Files generated for each hal file + each type in HAL files
     47 };
     48 
     49 // Represents a file that is generated by an -L option for an FQName
     50 struct FileGenerator {
     51     using ShouldGenerateFunction = std::function<bool(const FQName& fqName)>;
     52     using FileNameForFQName = std::function<std::string(const FQName& fqName)>;
     53     using GenerationFunction = std::function<status_t(Formatter& out, const FQName& fqName,
     54                                                       const Coordinator* coordinator)>;
     55 
     56     ShouldGenerateFunction mShouldGenerateForFqName;  // If generate function applies to this target
     57     FileNameForFQName mFileNameForFqName;             // Target -> filename
     58     GenerationFunction mGenerationFunction;           // Function to generate output for file
     59 
     60     std::string getFileName(const FQName& fqName) const {
     61         return mFileNameForFqName ? mFileNameForFqName(fqName) : "";
     62     }
     63 
     64     status_t getOutputFile(const FQName& fqName, const Coordinator* coordinator,
     65                            Coordinator::Location location, std::string* file) const {
     66         if (!mShouldGenerateForFqName(fqName)) {
     67             return OK;
     68         }
     69 
     70         return coordinator->getFilepath(fqName, location, getFileName(fqName), file);
     71     }
     72 
     73     status_t appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
     74                                Coordinator::Location location,
     75                                std::vector<std::string>* outputFiles) const {
     76         if (location == Coordinator::Location::STANDARD_OUT) {
     77             return OK;
     78         }
     79 
     80         if (mShouldGenerateForFqName(fqName)) {
     81             std::string fileName;
     82             status_t err = getOutputFile(fqName, coordinator, location, &fileName);
     83             if (err != OK) return err;
     84 
     85             if (!fileName.empty()) {
     86                 outputFiles->push_back(fileName);
     87             }
     88         }
     89         return OK;
     90     }
     91 
     92     status_t generate(const FQName& fqName, const Coordinator* coordinator,
     93                       Coordinator::Location location) const {
     94         CHECK(mShouldGenerateForFqName != nullptr);
     95         CHECK(mGenerationFunction != nullptr);
     96 
     97         if (!mShouldGenerateForFqName(fqName)) {
     98             return OK;
     99         }
    100 
    101         Formatter out = coordinator->getFormatter(fqName, location, getFileName(fqName));
    102         if (!out.isValid()) {
    103             return UNKNOWN_ERROR;
    104         }
    105 
    106         return mGenerationFunction(out, fqName, coordinator);
    107     }
    108 
    109     // Helper methods for filling out this struct
    110     static bool generateForTypes(const FQName& fqName) {
    111         const auto names = fqName.names();
    112         return names.size() > 0 && names[0] == "types";
    113     }
    114     static bool generateForInterfaces(const FQName& fqName) { return !generateForTypes(fqName); }
    115     static bool alwaysGenerate(const FQName&) { return true; }
    116 };
    117 
    118 // Represents a -L option, takes a fqName and generates files
    119 struct OutputHandler {
    120     using ValidationFunction = std::function<bool(
    121         const FQName& fqName, const Coordinator* coordinator, const std::string& language)>;
    122 
    123     std::string mKey;                 // -L in Android.bp
    124     std::string mDescription;         // for display in help menu
    125     OutputMode mOutputMode;           // how this option interacts with -o
    126     Coordinator::Location mLocation;  // how to compute location relative to the output directory
    127     GenerationGranularity mGenerationGranularity;   // what to run generate function on
    128     ValidationFunction mValidate;                   // if a given fqName is allowed for this option
    129     std::vector<FileGenerator> mGenerateFunctions;  // run for each target at this granularity
    130 
    131     const std::string& name() const { return mKey; }
    132     const std::string& description() const { return mDescription; }
    133 
    134     status_t generate(const FQName& fqName, const Coordinator* coordinator) const;
    135     status_t validate(const FQName& fqName, const Coordinator* coordinator,
    136                       const std::string& language) const {
    137         return mValidate(fqName, coordinator, language);
    138     }
    139 
    140     status_t writeDepFile(const FQName& fqName, const Coordinator* coordinator) const;
    141 
    142    private:
    143     status_t appendTargets(const FQName& fqName, const Coordinator* coordinator,
    144                            std::vector<FQName>* targets) const;
    145     status_t appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
    146                                std::vector<std::string>* outputFiles) const;
    147 };
    148 
    149 // Helper method for GenerationGranularity::PER_TYPE
    150 // IFoo -> IFoo, types.hal (containing Bar, Baz) -> types.Bar, types.Baz
    151 static status_t appendPerTypeTargets(const FQName& fqName, const Coordinator* coordinator,
    152                                      std::vector<FQName>* exportedPackageInterfaces) {
    153     CHECK(fqName.isFullyQualified());
    154     if (fqName.name() != "types") {
    155         exportedPackageInterfaces->push_back(fqName);
    156         return OK;
    157     }
    158 
    159     AST* typesAST = coordinator->parse(fqName);
    160     if (typesAST == nullptr) {
    161         fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
    162         return UNKNOWN_ERROR;
    163     }
    164 
    165     std::vector<NamedType*> rootTypes = typesAST->getRootScope()->getSubTypes();
    166     for (const NamedType* rootType : rootTypes) {
    167         if (rootType->isTypeDef()) continue;
    168 
    169         FQName rootTypeName(fqName.package(), fqName.version(), "types." + rootType->localName());
    170         exportedPackageInterfaces->push_back(rootTypeName);
    171     }
    172     return OK;
    173 }
    174 
    175 status_t OutputHandler::appendTargets(const FQName& fqName, const Coordinator* coordinator,
    176                                       std::vector<FQName>* targets) const {
    177     switch (mGenerationGranularity) {
    178         case GenerationGranularity::PER_PACKAGE: {
    179             targets->push_back(fqName.getPackageAndVersion());
    180         } break;
    181         case GenerationGranularity::PER_FILE: {
    182             if (fqName.isFullyQualified()) {
    183                 targets->push_back(fqName);
    184                 break;
    185             }
    186             status_t err = coordinator->appendPackageInterfacesToVector(fqName, targets);
    187             if (err != OK) return err;
    188         } break;
    189         case GenerationGranularity::PER_TYPE: {
    190             if (fqName.isFullyQualified()) {
    191                 status_t err = appendPerTypeTargets(fqName, coordinator, targets);
    192                 if (err != OK) return err;
    193             }
    194 
    195             std::vector<FQName> packageInterfaces;
    196             status_t err = coordinator->appendPackageInterfacesToVector(fqName, &packageInterfaces);
    197             if (err != OK) return err;
    198             for (const FQName& packageInterface : packageInterfaces) {
    199                 err = appendPerTypeTargets(packageInterface, coordinator, targets);
    200                 if (err != OK) return err;
    201             }
    202         } break;
    203         default:
    204             CHECK(!"Should be here");
    205     }
    206 
    207     return OK;
    208 }
    209 
    210 status_t OutputHandler::generate(const FQName& fqName, const Coordinator* coordinator) const {
    211     std::vector<FQName> targets;
    212     status_t err = appendTargets(fqName, coordinator, &targets);
    213     if (err != OK) return err;
    214 
    215     for (const FQName& fqName : targets) {
    216         for (const FileGenerator& file : mGenerateFunctions) {
    217             status_t err = file.generate(fqName, coordinator, mLocation);
    218             if (err != OK) return err;
    219         }
    220     }
    221 
    222     return OK;
    223 }
    224 
    225 status_t OutputHandler::appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
    226                                           std::vector<std::string>* outputFiles) const {
    227     std::vector<FQName> targets;
    228     status_t err = appendTargets(fqName, coordinator, &targets);
    229     if (err != OK) return err;
    230 
    231     for (const FQName& fqName : targets) {
    232         for (const FileGenerator& file : mGenerateFunctions) {
    233             err = file.appendOutputFiles(fqName, coordinator, mLocation, outputFiles);
    234             if (err != OK) return err;
    235         }
    236     }
    237 
    238     return OK;
    239 }
    240 
    241 status_t OutputHandler::writeDepFile(const FQName& fqName, const Coordinator* coordinator) const {
    242     std::vector<std::string> outputFiles;
    243     status_t err = appendOutputFiles(fqName, coordinator, &outputFiles);
    244     if (err != OK) return err;
    245 
    246     // No need for dep files
    247     if (outputFiles.empty()) {
    248         return OK;
    249     }
    250 
    251     // Depfiles in Android for genrules should be for the 'main file'. Because hidl-gen doesn't have
    252     // a main file for most targets, we are just outputting a depfile for one single file only.
    253     const std::string forFile = outputFiles[0];
    254 
    255     return coordinator->writeDepFile(forFile);
    256 }
    257 
    258 // Use an AST function as a OutputHandler GenerationFunction
    259 static FileGenerator::GenerationFunction astGenerationFunction(void (AST::*generate)(Formatter&)
    260                                                                    const = nullptr) {
    261     return [generate](Formatter& out, const FQName& fqName,
    262                       const Coordinator* coordinator) -> status_t {
    263         AST* ast = coordinator->parse(fqName);
    264         if (ast == nullptr) {
    265             fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
    266             return UNKNOWN_ERROR;
    267         }
    268 
    269         if (generate == nullptr) return OK;  // just parsing AST
    270         (ast->*generate)(out);
    271 
    272         return OK;
    273     };
    274 }
    275 
    276 // Common pattern: single file for package or standard out
    277 static FileGenerator singleFileGenerator(
    278     const std::string& fileName, const FileGenerator::GenerationFunction& generationFunction) {
    279     return {
    280         FileGenerator::alwaysGenerate, [fileName](const FQName&) { return fileName; },
    281         generationFunction,
    282     };
    283 }
    284 
    285 static status_t generateJavaForPackage(Formatter& out, const FQName& fqName,
    286                                        const Coordinator* coordinator) {
    287     AST* ast;
    288     std::string limitToType;
    289 
    290     // Required for legacy -Lmakefile files
    291     if (fqName.name().find("types.") == 0) {
    292         limitToType = fqName.name().substr(strlen("types."));
    293 
    294         FQName typesName = fqName.getTypesForPackage();
    295         ast = coordinator->parse(typesName);
    296     } else {
    297         ast = coordinator->parse(fqName);
    298     }
    299     if (ast == nullptr) {
    300         fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
    301         return UNKNOWN_ERROR;
    302     }
    303     ast->generateJava(out, limitToType);
    304     return OK;
    305 };
    306 
    307 static status_t dumpDefinedButUnreferencedTypeNames(const FQName& packageFQName,
    308                                                     const Coordinator* coordinator) {
    309     std::vector<FQName> packageInterfaces;
    310     status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
    311     if (err != OK) return err;
    312 
    313     std::set<FQName> unreferencedDefinitions;
    314     std::set<FQName> unreferencedImports;
    315     err = coordinator->addUnreferencedTypes(packageInterfaces, &unreferencedDefinitions,
    316                                             &unreferencedImports);
    317     if (err != OK) return err;
    318 
    319     for (const auto& fqName : unreferencedDefinitions) {
    320         std::cerr
    321             << "VERBOSE: DEFINED-BUT-NOT-REFERENCED "
    322             << fqName.string()
    323             << std::endl;
    324     }
    325 
    326     for (const auto& fqName : unreferencedImports) {
    327         std::cerr
    328             << "VERBOSE: IMPORTED-BUT-NOT-REFERENCED "
    329             << fqName.string()
    330             << std::endl;
    331     }
    332 
    333     return OK;
    334 }
    335 
    336 static std::string makeLibraryName(const FQName &packageFQName) {
    337     return packageFQName.string();
    338 }
    339 
    340 static status_t isPackageJavaCompatible(const FQName& packageFQName, const Coordinator* coordinator,
    341                                         bool* compatible) {
    342     std::vector<FQName> todo;
    343     status_t err =
    344         coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
    345 
    346     if (err != OK) {
    347         return err;
    348     }
    349 
    350     std::set<FQName> seen;
    351     for (const auto &iface : todo) {
    352         seen.insert(iface);
    353     }
    354 
    355     // Form the transitive closure of all imported interfaces (and types.hal-s)
    356     // If any one of them is not java compatible, this package isn't either.
    357     while (!todo.empty()) {
    358         const FQName fqName = todo.back();
    359         todo.pop_back();
    360 
    361         AST *ast = coordinator->parse(fqName);
    362 
    363         if (ast == nullptr) {
    364             return UNKNOWN_ERROR;
    365         }
    366 
    367         if (!ast->isJavaCompatible()) {
    368             *compatible = false;
    369             return OK;
    370         }
    371 
    372         std::set<FQName> importedPackages;
    373         ast->getImportedPackages(&importedPackages);
    374 
    375         for (const auto &package : importedPackages) {
    376             std::vector<FQName> packageInterfaces;
    377             status_t err = coordinator->appendPackageInterfacesToVector(
    378                     package, &packageInterfaces);
    379 
    380             if (err != OK) {
    381                 return err;
    382             }
    383 
    384             for (const auto &iface : packageInterfaces) {
    385                 if (seen.find(iface) != seen.end()) {
    386                     continue;
    387                 }
    388 
    389                 todo.push_back(iface);
    390                 seen.insert(iface);
    391             }
    392         }
    393     }
    394 
    395     *compatible = true;
    396     return OK;
    397 }
    398 
    399 static bool packageNeedsJavaCode(
    400         const std::vector<FQName> &packageInterfaces, AST *typesAST) {
    401     if (packageInterfaces.size() == 0) {
    402         return false;
    403     }
    404 
    405     // If there is more than just a types.hal file to this package we'll
    406     // definitely need to generate Java code.
    407     if (packageInterfaces.size() > 1
    408             || packageInterfaces[0].name() != "types") {
    409         return true;
    410     }
    411 
    412     CHECK(typesAST != nullptr);
    413 
    414     // We'll have to generate Java code if types.hal contains any non-typedef
    415     // type declarations.
    416 
    417     Scope* rootScope = typesAST->getRootScope();
    418     std::vector<NamedType *> subTypes = rootScope->getSubTypes();
    419 
    420     for (const auto &subType : subTypes) {
    421         if (!subType->isTypeDef()) {
    422             return true;
    423         }
    424     }
    425 
    426     return false;
    427 }
    428 
    429 bool validateIsPackage(const FQName& fqName, const Coordinator*,
    430                        const std::string& /* language */) {
    431     if (fqName.package().empty()) {
    432         fprintf(stderr, "ERROR: Expecting package name\n");
    433         return false;
    434     }
    435 
    436     if (fqName.version().empty()) {
    437         fprintf(stderr, "ERROR: Expecting package version\n");
    438         return false;
    439     }
    440 
    441     if (!fqName.name().empty()) {
    442         fprintf(stderr,
    443                 "ERROR: Expecting only package name and version.\n");
    444         return false;
    445     }
    446 
    447     return true;
    448 }
    449 
    450 bool isHidlTransportPackage(const FQName& fqName) {
    451     return fqName.package() == gIBaseFqName.package() ||
    452            fqName.package() == gIManagerFqName.package();
    453 }
    454 
    455 bool isSystemProcessSupportedPackage(const FQName& fqName) {
    456     // Technically, so is hidl IBase + IServiceManager, but
    457     // these are part of libhidltransport.
    458     return fqName.string() == "android.hardware.graphics.common (at) 1.0" ||
    459            fqName.string() == "android.hardware.graphics.common (at) 1.1" ||
    460            fqName.string() == "android.hardware.graphics.mapper (at) 2.0" ||
    461            fqName.string() == "android.hardware.graphics.mapper (at) 2.1" ||
    462            fqName.string() == "android.hardware.renderscript (at) 1.0" ||
    463            fqName.string() == "android.hidl.memory.token (at) 1.0" ||
    464            fqName.string() == "android.hidl.memory (at) 1.0";
    465 }
    466 
    467 bool isSystemPackage(const FQName &package) {
    468     return package.inPackage("android.hidl") ||
    469            package.inPackage("android.system") ||
    470            package.inPackage("android.frameworks") ||
    471            package.inPackage("android.hardware");
    472 }
    473 
    474 // TODO(b/69862859): remove special case
    475 status_t isTestPackage(const FQName& fqName, const Coordinator* coordinator, bool* isTestPackage) {
    476     const auto fileExists = [](const std::string& file) {
    477         struct stat buf;
    478         return stat(file.c_str(), &buf) == 0;
    479     };
    480 
    481     std::string path;
    482     status_t err = coordinator->getFilepath(fqName, Coordinator::Location::PACKAGE_ROOT,
    483                                             ".hidl_for_test", &path);
    484     if (err != OK) return err;
    485 
    486     const bool exists = fileExists(path);
    487 
    488     if (exists) {
    489         coordinator->onFileAccess(path, "r");
    490     }
    491 
    492     *isTestPackage = exists;
    493     return OK;
    494 }
    495 
    496 static status_t generateAdapterMainSource(Formatter& out, const FQName& packageFQName,
    497                                           const Coordinator* coordinator) {
    498     std::vector<FQName> packageInterfaces;
    499     status_t err =
    500         coordinator->appendPackageInterfacesToVector(packageFQName,
    501                                                      &packageInterfaces);
    502     if (err != OK) {
    503         return err;
    504     }
    505 
    506     out << "#include <hidladapter/HidlBinderAdapter.h>\n";
    507 
    508     for (auto &interface : packageInterfaces) {
    509         if (interface.name() == "types") {
    510             continue;
    511         }
    512         AST::generateCppPackageInclude(out, interface, interface.getInterfaceAdapterName());
    513     }
    514 
    515     out << "int main(int argc, char** argv) ";
    516     out.block([&] {
    517         out << "return ::android::hardware::adapterMain<\n";
    518         out.indent();
    519         for (auto &interface : packageInterfaces) {
    520             if (interface.name() == "types") {
    521                 continue;
    522             }
    523             out << interface.getInterfaceAdapterFqName().cppName();
    524 
    525             if (&interface != &packageInterfaces.back()) {
    526                 out << ",\n";
    527             }
    528         }
    529         out << ">(\"" << packageFQName.string() << "\", argc, argv);\n";
    530         out.unindent();
    531     }).endl();
    532     return OK;
    533 }
    534 
    535 static status_t generateAndroidBpForPackage(Formatter& out, const FQName& packageFQName,
    536                                             const Coordinator* coordinator) {
    537     CHECK(packageFQName.isValid() && !packageFQName.isFullyQualified() &&
    538           packageFQName.name().empty());
    539 
    540     std::vector<FQName> packageInterfaces;
    541 
    542     status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
    543 
    544     if (err != OK) {
    545         return err;
    546     }
    547 
    548     std::set<FQName> importedPackagesHierarchy;
    549     std::vector<const Type *> exportedTypes;
    550     AST* typesAST = nullptr;
    551 
    552     for (const auto& fqName : packageInterfaces) {
    553         AST* ast = coordinator->parse(fqName);
    554 
    555         if (ast == NULL) {
    556             fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
    557 
    558             return UNKNOWN_ERROR;
    559         }
    560 
    561         if (fqName.name() == "types") {
    562             typesAST = ast;
    563         }
    564 
    565         ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
    566         ast->appendToExportedTypesVector(&exportedTypes);
    567     }
    568 
    569     bool needsJavaCode = packageNeedsJavaCode(packageInterfaces, typesAST);
    570 
    571     bool genJavaConstants = needsJavaCode && !exportedTypes.empty();
    572 
    573     bool isJavaCompatible;
    574     err = isPackageJavaCompatible(packageFQName, coordinator, &isJavaCompatible);
    575     if (err != OK) return err;
    576     bool genJavaLibrary = needsJavaCode && isJavaCompatible;
    577 
    578     bool generateForTest;
    579     err = isTestPackage(packageFQName, coordinator, &generateForTest);
    580     if (err != OK) return err;
    581 
    582     bool isVndk = !generateForTest && isSystemPackage(packageFQName);
    583     bool isVndkSp = isVndk && isSystemProcessSupportedPackage(packageFQName);
    584 
    585     std::string packageRoot;
    586     err = coordinator->getPackageRoot(packageFQName, &packageRoot);
    587     if (err != OK) return err;
    588 
    589     out << "// This file is autogenerated by hidl-gen -Landroidbp.\n\n";
    590 
    591     out << "hidl_interface ";
    592     out.block([&] {
    593         out << "name: \"" << makeLibraryName(packageFQName) << "\",\n";
    594         if (!coordinator->getOwner().empty()) {
    595             out << "owner: \"" << coordinator->getOwner() << "\",\n";
    596         }
    597         out << "root: \"" << packageRoot << "\",\n";
    598         if (isHidlTransportPackage(packageFQName)) {
    599             out << "core_interface: true,\n";
    600         }
    601         if (isVndk) {
    602             out << "vndk: ";
    603             out.block([&]() {
    604                 out << "enabled: true,\n";
    605                 if (isVndkSp) {
    606                     out << "support_system_process: true,\n";
    607                 }
    608             }) << ",\n";
    609         }
    610         (out << "srcs: [\n").indent([&] {
    611            for (const auto& fqName : packageInterfaces) {
    612                out << "\"" << fqName.name() << ".hal\",\n";
    613            }
    614         }) << "],\n";
    615         if (!importedPackagesHierarchy.empty()) {
    616             (out << "interfaces: [\n").indent([&] {
    617                for (const auto& fqName : importedPackagesHierarchy) {
    618                    out << "\"" << fqName.string() << "\",\n";
    619                }
    620             }) << "],\n";
    621         }
    622         if (typesAST != nullptr) {
    623             (out << "types: [\n").indent([&] {
    624                 std::vector<NamedType *> subTypes = typesAST->getRootScope()->getSubTypes();
    625                 std::sort(
    626                         subTypes.begin(),
    627                         subTypes.end(),
    628                         [](const NamedType *a, const NamedType *b) -> bool {
    629                             return a->fqName() < b->fqName();
    630                         });
    631 
    632                 for (const auto &type : subTypes) {
    633                     if (type->isTypeDef()) {
    634                         continue;
    635                     }
    636 
    637                     out << "\"" << type->localName() << "\",\n";
    638                 }
    639             }) << "],\n";
    640         }
    641         // Explicity call this out for developers.
    642         out << "gen_java: " << (genJavaLibrary ? "true" : "false") << ",\n";
    643         if (genJavaConstants) {
    644             out << "gen_java_constants: true,\n";
    645         }
    646    }).endl().endl();
    647 
    648     return OK;
    649 }
    650 
    651 static status_t generateAndroidBpImplForPackage(Formatter& out, const FQName& packageFQName,
    652                                                 const Coordinator* coordinator) {
    653     const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
    654 
    655     std::vector<FQName> packageInterfaces;
    656 
    657     status_t err =
    658         coordinator->appendPackageInterfacesToVector(packageFQName,
    659                                                      &packageInterfaces);
    660 
    661     if (err != OK) {
    662         return err;
    663     }
    664 
    665     std::set<FQName> importedPackages;
    666 
    667     for (const auto &fqName : packageInterfaces) {
    668         AST *ast = coordinator->parse(fqName);
    669 
    670         if (ast == NULL) {
    671             fprintf(stderr,
    672                     "ERROR: Could not parse %s. Aborting.\n",
    673                     fqName.string().c_str());
    674 
    675             return UNKNOWN_ERROR;
    676         }
    677 
    678         ast->getImportedPackages(&importedPackages);
    679     }
    680 
    681     out << "cc_library_shared {\n";
    682     out.indent([&] {
    683         out << "// FIXME: this should only be -impl for a passthrough hal.\n"
    684             << "// In most cases, to convert this to a binderized implementation, you should:\n"
    685             << "// - change '-impl' to '-service' here and make it a cc_binary instead of a\n"
    686             << "//   cc_library_shared.\n"
    687             << "// - add a *.rc file for this module.\n"
    688             << "// - delete HIDL_FETCH_I* functions.\n"
    689             << "// - call configureRpcThreadpool and registerAsService on the instance.\n"
    690             << "// You may also want to append '-impl/-service' with a specific identifier like\n"
    691             << "// '-vendor' or '-<hardware identifier>' etc to distinguish it.\n";
    692         out << "name: \"" << libraryName << "\",\n";
    693         if (!coordinator->getOwner().empty()) {
    694             out << "owner: \"" << coordinator->getOwner() << "\",\n";
    695         }
    696         out << "relative_install_path: \"hw\",\n";
    697         if (coordinator->getOwner().empty()) {
    698             out << "// FIXME: this should be 'vendor: true' for modules that will eventually be\n"
    699                    "// on AOSP.\n";
    700         }
    701         out << "proprietary: true,\n";
    702         out << "srcs: [\n";
    703         out.indent([&] {
    704             for (const auto &fqName : packageInterfaces) {
    705                 if (fqName.name() == "types") {
    706                     continue;
    707                 }
    708                 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
    709             }
    710         });
    711         out << "],\n"
    712             << "shared_libs: [\n";
    713         out.indent([&] {
    714             out << "\"libhidlbase\",\n"
    715                 << "\"libhidltransport\",\n"
    716                 << "\"libutils\",\n"
    717                 << "\"" << makeLibraryName(packageFQName) << "\",\n";
    718 
    719             for (const auto &importedPackage : importedPackages) {
    720                 if (isHidlTransportPackage(importedPackage)) {
    721                     continue;
    722                 }
    723 
    724                 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
    725             }
    726         });
    727         out << "],\n";
    728     });
    729     out << "}\n";
    730 
    731     return OK;
    732 }
    733 
    734 bool validateForSource(const FQName& fqName, const Coordinator* coordinator,
    735                        const std::string& language) {
    736     if (fqName.package().empty()) {
    737         fprintf(stderr, "ERROR: Expecting package name\n");
    738         return false;
    739     }
    740 
    741     if (fqName.version().empty()) {
    742         fprintf(stderr, "ERROR: Expecting package version\n");
    743         return false;
    744     }
    745 
    746     const std::string &name = fqName.name();
    747     if (!name.empty()) {
    748         if (name.find('.') == std::string::npos) {
    749             return true;
    750         }
    751 
    752         if (language != "java" || name.find("types.") != 0) {
    753             // When generating java sources for "types.hal", output can be
    754             // constrained to just one of the top-level types declared
    755             // by using the extended syntax
    756             // android.hardware.Foo (at) 1.0::types.TopLevelTypeName.
    757             // In all other cases (different language, not 'types') the dot
    758             // notation in the name is illegal in this context.
    759             return false;
    760         }
    761 
    762         return true;
    763     }
    764 
    765     if (language == "java") {
    766         bool isJavaCompatible;
    767         status_t err = isPackageJavaCompatible(fqName, coordinator, &isJavaCompatible);
    768         if (err != OK) return false;
    769 
    770         if (!isJavaCompatible) {
    771             fprintf(stderr,
    772                     "ERROR: %s is not Java compatible. The Java backend"
    773                     " does NOT support union types nor native handles. "
    774                     "In addition, vectors of arrays are limited to at most "
    775                     "one-dimensional arrays and vectors of {vectors,interfaces} are"
    776                     " not supported.\n",
    777                     fqName.string().c_str());
    778             return false;
    779         }
    780     }
    781 
    782     return true;
    783 }
    784 
    785 FileGenerator::GenerationFunction generateExportHeaderForPackage(bool forJava) {
    786     return [forJava](Formatter& out, const FQName& packageFQName,
    787                      const Coordinator* coordinator) -> status_t {
    788         CHECK(packageFQName.isValid()
    789                 && !packageFQName.package().empty()
    790                 && !packageFQName.version().empty()
    791                 && packageFQName.name().empty());
    792 
    793         std::vector<FQName> packageInterfaces;
    794 
    795         status_t err = coordinator->appendPackageInterfacesToVector(
    796                 packageFQName, &packageInterfaces);
    797 
    798         if (err != OK) {
    799             return err;
    800         }
    801 
    802         std::vector<const Type *> exportedTypes;
    803 
    804         for (const auto &fqName : packageInterfaces) {
    805             AST *ast = coordinator->parse(fqName);
    806 
    807             if (ast == NULL) {
    808                 fprintf(stderr,
    809                         "ERROR: Could not parse %s. Aborting.\n",
    810                         fqName.string().c_str());
    811 
    812                 return UNKNOWN_ERROR;
    813             }
    814 
    815             ast->appendToExportedTypesVector(&exportedTypes);
    816         }
    817 
    818         if (exportedTypes.empty()) {
    819             return OK;
    820         }
    821 
    822         if (!out.isValid()) {
    823             return UNKNOWN_ERROR;
    824         }
    825 
    826         std::string packagePath;
    827         err = coordinator->getPackagePath(packageFQName, false /* relative */,
    828                                           false /* sanitized */, &packagePath);
    829         if (err != OK) return err;
    830 
    831         out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
    832             << "// Source: " << packageFQName.string() << "\n"
    833             << "// Location: " << packagePath << "\n\n";
    834 
    835         std::string guard;
    836         if (forJava) {
    837             out << "package " << packageFQName.javaPackage() << ";\n\n";
    838             out << "public class Constants {\n";
    839             out.indent();
    840         } else {
    841             guard = "HIDL_GENERATED_";
    842             guard += StringHelper::Uppercase(packageFQName.tokenName());
    843             guard += "_";
    844             guard += "EXPORTED_CONSTANTS_H_";
    845 
    846             out << "#ifndef "
    847                 << guard
    848                 << "\n#define "
    849                 << guard
    850                 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
    851         }
    852 
    853         for (const auto &type : exportedTypes) {
    854             type->emitExportedHeader(out, forJava);
    855         }
    856 
    857         if (forJava) {
    858             out.unindent();
    859             out << "}\n";
    860         } else {
    861             out << "#ifdef __cplusplus\n}\n#endif\n\n#endif  // "
    862                 << guard
    863                 << "\n";
    864         }
    865 
    866         return OK;
    867     };
    868 }
    869 
    870 static status_t generateHashOutput(Formatter& out, const FQName& fqName,
    871                                    const Coordinator* coordinator) {
    872     CHECK(fqName.isFullyQualified());
    873 
    874     AST* ast = coordinator->parse(fqName, {} /* parsed */,
    875                                   Coordinator::Enforce::NO_HASH /* enforcement */);
    876 
    877     if (ast == NULL) {
    878         fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
    879 
    880         return UNKNOWN_ERROR;
    881     }
    882 
    883     out << Hash::getHash(ast->getFilename()).hexString() << " " << fqName.string() << "\n";
    884 
    885     return OK;
    886 }
    887 
    888 template <typename T>
    889 std::vector<T> operator+(const std::vector<T>& lhs, const std::vector<T>& rhs) {
    890     std::vector<T> ret;
    891     ret.reserve(lhs.size() + rhs.size());
    892     ret.insert(ret.begin(), lhs.begin(), lhs.end());
    893     ret.insert(ret.end(), rhs.begin(), rhs.end());
    894     return ret;
    895 }
    896 
    897 // clang-format off
    898 static const std::vector<FileGenerator> kCppHeaderFormats = {
    899     {
    900         FileGenerator::alwaysGenerate,
    901         [](const FQName& fqName) { return fqName.name() + ".h"; },
    902         astGenerationFunction(&AST::generateInterfaceHeader),
    903     },
    904     {
    905         FileGenerator::alwaysGenerate,
    906         [](const FQName& fqName) {
    907             return fqName.isInterfaceName() ? fqName.getInterfaceHwName() + ".h" : "hwtypes.h";
    908         },
    909         astGenerationFunction(&AST::generateHwBinderHeader),
    910     },
    911     {
    912         FileGenerator::generateForInterfaces,
    913         [](const FQName& fqName) { return fqName.getInterfaceStubName() + ".h"; },
    914         astGenerationFunction(&AST::generateStubHeader),
    915     },
    916     {
    917         FileGenerator::generateForInterfaces,
    918         [](const FQName& fqName) { return fqName.getInterfaceProxyName() + ".h"; },
    919         astGenerationFunction(&AST::generateProxyHeader),
    920     },
    921     {
    922         FileGenerator::generateForInterfaces,
    923         [](const FQName& fqName) { return fqName.getInterfacePassthroughName() + ".h"; },
    924         astGenerationFunction(&AST::generatePassthroughHeader),
    925     },
    926 };
    927 
    928 static const std::vector<FileGenerator> kCppSourceFormats = {
    929     {
    930         FileGenerator::alwaysGenerate,
    931         [](const FQName& fqName) {
    932             return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + "All.cpp" : "types.cpp";
    933         },
    934         astGenerationFunction(&AST::generateCppSource),
    935     },
    936 };
    937 
    938 static const std::vector<FileGenerator> kCppImplHeaderFormats = {
    939     {
    940         FileGenerator::generateForInterfaces,
    941         [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".h"; },
    942         astGenerationFunction(&AST::generateCppImplHeader),
    943     },
    944 };
    945 
    946 static const std::vector<FileGenerator> kCppImplSourceFormats = {
    947     {
    948         FileGenerator::generateForInterfaces,
    949         [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".cpp"; },
    950         astGenerationFunction(&AST::generateCppImplSource),
    951     },
    952 };
    953 
    954 static const std::vector<FileGenerator> kCppAdapterHeaderFormats = {
    955     {
    956         FileGenerator::alwaysGenerate,
    957         [](const FQName& fqName) {
    958             return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".h" : "Atypes.h";
    959         },
    960         astGenerationFunction(&AST::generateCppAdapterHeader),
    961     },
    962 };
    963 
    964 static const std::vector<FileGenerator> kCppAdapterSourceFormats = {
    965     {
    966         FileGenerator::alwaysGenerate,
    967         [](const FQName& fqName) {
    968             return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".cpp" : "Atypes.cpp";
    969         },
    970         astGenerationFunction(&AST::generateCppAdapterSource),
    971     },
    972 };
    973 
    974 static const std::vector<OutputHandler> kFormats = {
    975     {
    976         "check",
    977         "Parses the interface to see if valid but doesn't write any files.",
    978         OutputMode::NOT_NEEDED,
    979         Coordinator::Location::STANDARD_OUT,
    980         GenerationGranularity::PER_FILE,
    981         validateForSource,
    982         {
    983             {
    984                 FileGenerator::alwaysGenerate,
    985                 nullptr /* filename for fqname */,
    986                 astGenerationFunction(),
    987             },
    988         },
    989     },
    990     {
    991         "c++",
    992         "(internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.",
    993         OutputMode::NEEDS_DIR,
    994         Coordinator::Location::GEN_OUTPUT,
    995         GenerationGranularity::PER_FILE,
    996         validateForSource,
    997         kCppHeaderFormats + kCppSourceFormats,
    998     },
    999     {
   1000         "c++-headers",
   1001         "(internal) Generates C++ headers for interface files for talking to HIDL interfaces.",
   1002         OutputMode::NEEDS_DIR,
   1003         Coordinator::Location::GEN_OUTPUT,
   1004         GenerationGranularity::PER_FILE,
   1005         validateForSource,
   1006         kCppHeaderFormats,
   1007     },
   1008     {
   1009         "c++-sources",
   1010         "(internal) Generates C++ sources for interface files for talking to HIDL interfaces.",
   1011         OutputMode::NEEDS_DIR,
   1012         Coordinator::Location::GEN_OUTPUT,
   1013         GenerationGranularity::PER_FILE,
   1014         validateForSource,
   1015         kCppSourceFormats,
   1016     },
   1017     {
   1018         "export-header",
   1019         "Generates a header file from @export enumerations to help maintain legacy code.",
   1020         OutputMode::NEEDS_FILE,
   1021         Coordinator::Location::DIRECT,
   1022         GenerationGranularity::PER_PACKAGE,
   1023         validateIsPackage,
   1024         {singleFileGenerator("", generateExportHeaderForPackage(false /* forJava */))}
   1025     },
   1026     {
   1027         "c++-impl",
   1028         "Generates boilerplate implementation of a hidl interface in C++ (for convenience).",
   1029         OutputMode::NEEDS_DIR,
   1030         Coordinator::Location::DIRECT,
   1031         GenerationGranularity::PER_FILE,
   1032         validateForSource,
   1033         kCppImplHeaderFormats + kCppImplSourceFormats,
   1034     },
   1035     {
   1036         "c++-impl-headers",
   1037         "c++-impl but headers only",
   1038         OutputMode::NEEDS_DIR,
   1039         Coordinator::Location::DIRECT,
   1040         GenerationGranularity::PER_FILE,
   1041         validateForSource,
   1042         kCppImplHeaderFormats,
   1043     },
   1044     {
   1045         "c++-impl-sources",
   1046         "c++-impl but sources only",
   1047         OutputMode::NEEDS_DIR,
   1048         Coordinator::Location::DIRECT,
   1049         GenerationGranularity::PER_FILE,
   1050         validateForSource,
   1051         kCppImplSourceFormats,
   1052     },
   1053     {
   1054         "c++-adapter",
   1055         "Takes a x.(y+n) interface and mocks an x.y interface.",
   1056         OutputMode::NEEDS_DIR,
   1057         Coordinator::Location::GEN_OUTPUT,
   1058         GenerationGranularity::PER_FILE,
   1059         validateForSource,
   1060         kCppAdapterHeaderFormats + kCppAdapterSourceFormats,
   1061     },
   1062     {
   1063         "c++-adapter-headers",
   1064         "c++-adapter but helper headers only",
   1065         OutputMode::NEEDS_DIR,
   1066         Coordinator::Location::GEN_OUTPUT,
   1067         GenerationGranularity::PER_FILE,
   1068         validateForSource,
   1069         kCppAdapterHeaderFormats,
   1070     },
   1071     {
   1072         "c++-adapter-sources",
   1073         "c++-adapter but helper sources only",
   1074         OutputMode::NEEDS_DIR,
   1075         Coordinator::Location::GEN_OUTPUT,
   1076         GenerationGranularity::PER_FILE,
   1077         validateForSource,
   1078         kCppAdapterSourceFormats,
   1079     },
   1080     {
   1081         "c++-adapter-main",
   1082         "c++-adapter but the adapter binary source only",
   1083         OutputMode::NEEDS_DIR,
   1084         Coordinator::Location::DIRECT,
   1085         GenerationGranularity::PER_PACKAGE,
   1086         validateIsPackage,
   1087         {singleFileGenerator("main.cpp", generateAdapterMainSource)},
   1088     },
   1089     {
   1090         "java",
   1091         "(internal) Generates Java library for talking to HIDL interfaces in Java.",
   1092         OutputMode::NEEDS_DIR,
   1093         Coordinator::Location::GEN_SANITIZED,
   1094         GenerationGranularity::PER_TYPE,
   1095         validateForSource,
   1096         {
   1097             {
   1098                 FileGenerator::alwaysGenerate,
   1099                 [](const FQName& fqName) {
   1100                     return StringHelper::LTrim(fqName.name(), "types.") + ".java";
   1101                 },
   1102                 generateJavaForPackage,
   1103             },
   1104         }
   1105     },
   1106     {
   1107         "java-constants",
   1108         "(internal) Like export-header but for Java (always created by -Lmakefile if @export exists).",
   1109         OutputMode::NEEDS_DIR,
   1110         Coordinator::Location::GEN_SANITIZED,
   1111         GenerationGranularity::PER_PACKAGE,
   1112         validateIsPackage,
   1113         {singleFileGenerator("Constants.java", generateExportHeaderForPackage(true /* forJava */))}
   1114     },
   1115     {
   1116         "vts",
   1117         "(internal) Generates vts proto files for use in vtsd.",
   1118         OutputMode::NEEDS_DIR,
   1119         Coordinator::Location::GEN_OUTPUT,
   1120         GenerationGranularity::PER_FILE,
   1121         validateForSource,
   1122         {
   1123             {
   1124                 FileGenerator::alwaysGenerate,
   1125                 [](const FQName& fqName) {
   1126                     return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + ".vts" : "types.vts";
   1127                 },
   1128                 astGenerationFunction(&AST::generateVts),
   1129             },
   1130         }
   1131     },
   1132     {
   1133         "makefile",
   1134         "(removed) Used to generate makefiles for -Ljava and -Ljava-constants.",
   1135         OutputMode::NEEDS_SRC,
   1136         Coordinator::Location::PACKAGE_ROOT,
   1137         GenerationGranularity::PER_PACKAGE,
   1138         [](const FQName &, const Coordinator*, const std::string &) {
   1139            fprintf(stderr, "ERROR: makefile output is not supported. Use -Landroidbp for all build file generation.\n");
   1140            return false;
   1141         },
   1142         {},
   1143     },
   1144     {
   1145         "androidbp",
   1146         "(internal) Generates Soong bp files for -Lc++-headers, -Lc++-sources, -Ljava, -Ljava-constants, and -Lc++-adapter.",
   1147         OutputMode::NEEDS_SRC,
   1148         Coordinator::Location::PACKAGE_ROOT,
   1149         GenerationGranularity::PER_PACKAGE,
   1150         validateIsPackage,
   1151         {singleFileGenerator("Android.bp", generateAndroidBpForPackage)},
   1152     },
   1153     {
   1154         "androidbp-impl",
   1155         "Generates boilerplate bp files for implementation created with -Lc++-impl.",
   1156         OutputMode::NEEDS_DIR,
   1157         Coordinator::Location::DIRECT,
   1158         GenerationGranularity::PER_PACKAGE,
   1159         validateIsPackage,
   1160         {singleFileGenerator("Android.bp", generateAndroidBpImplForPackage)},
   1161     },
   1162     {
   1163         "hash",
   1164         "Prints hashes of interface in `current.txt` format to standard out.",
   1165         OutputMode::NOT_NEEDED,
   1166         Coordinator::Location::STANDARD_OUT,
   1167         GenerationGranularity::PER_FILE,
   1168         validateForSource,
   1169         {
   1170             {
   1171                 FileGenerator::alwaysGenerate,
   1172                 nullptr /* file name for fqName */,
   1173                 generateHashOutput,
   1174             },
   1175         }
   1176     },
   1177 };
   1178 // clang-format on
   1179 
   1180 static void usage(const char *me) {
   1181     fprintf(stderr,
   1182             "usage: %s [-p <root path>] -o <output path> -L <language> [-O <owner>] (-r <interface "
   1183             "root>)+ [-v] [-d <depfile>] FQNAME...\n\n",
   1184             me);
   1185 
   1186     fprintf(stderr,
   1187             "Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output.\n\n");
   1188 
   1189     fprintf(stderr, "         -h: Prints this menu.\n");
   1190     fprintf(stderr, "         -L <language>: The following options are available:\n");
   1191     for (auto& e : kFormats) {
   1192         fprintf(stderr, "            %-16s: %s\n", e.name().c_str(), e.description().c_str());
   1193     }
   1194     fprintf(stderr, "         -O <owner>: The owner of the module for -Landroidbp(-impl)?.\n");
   1195     fprintf(stderr, "         -o <output path>: Location to output files.\n");
   1196     fprintf(stderr, "         -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.\n");
   1197     fprintf(stderr, "         -r <package:path root>: E.g., android.hardware:hardware/interfaces.\n");
   1198     fprintf(stderr, "         -v: verbose output.\n");
   1199     fprintf(stderr, "         -d <depfile>: location of depfile to write to.\n");
   1200 }
   1201 
   1202 // hidl is intentionally leaky. Turn off LeakSanitizer by default.
   1203 extern "C" const char *__asan_default_options() {
   1204     return "detect_leaks=0";
   1205 }
   1206 
   1207 int main(int argc, char **argv) {
   1208     const char *me = argv[0];
   1209     if (argc == 1) {
   1210         usage(me);
   1211         exit(1);
   1212     }
   1213 
   1214     const OutputHandler* outputFormat = nullptr;
   1215     Coordinator coordinator;
   1216     std::string outputPath;
   1217 
   1218     int res;
   1219     while ((res = getopt(argc, argv, "hp:o:O:r:L:vd:")) >= 0) {
   1220         switch (res) {
   1221             case 'p': {
   1222                 if (!coordinator.getRootPath().empty()) {
   1223                     fprintf(stderr, "ERROR: -p <root path> can only be specified once.\n");
   1224                     exit(1);
   1225                 }
   1226                 coordinator.setRootPath(optarg);
   1227                 break;
   1228             }
   1229 
   1230             case 'v': {
   1231                 coordinator.setVerbose(true);
   1232                 break;
   1233             }
   1234 
   1235             case 'd': {
   1236                 coordinator.setDepFile(optarg);
   1237                 break;
   1238             }
   1239 
   1240             case 'o': {
   1241                 if (!outputPath.empty()) {
   1242                     fprintf(stderr, "ERROR: -o <output path> can only be specified once.\n");
   1243                     exit(1);
   1244                 }
   1245                 outputPath = optarg;
   1246                 break;
   1247             }
   1248 
   1249             case 'O': {
   1250                 if (!coordinator.getOwner().empty()) {
   1251                     fprintf(stderr, "ERROR: -O <owner> can only be specified once.\n");
   1252                     exit(1);
   1253                 }
   1254                 coordinator.setOwner(optarg);
   1255                 break;
   1256             }
   1257 
   1258             case 'r': {
   1259                 std::string val(optarg);
   1260                 auto index = val.find_first_of(':');
   1261                 if (index == std::string::npos) {
   1262                     fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
   1263                     exit(1);
   1264                 }
   1265 
   1266                 auto root = val.substr(0, index);
   1267                 auto path = val.substr(index + 1);
   1268 
   1269                 std::string error;
   1270                 status_t err = coordinator.addPackagePath(root, path, &error);
   1271                 if (err != OK) {
   1272                     fprintf(stderr, "%s\n", error.c_str());
   1273                     exit(1);
   1274                 }
   1275 
   1276                 break;
   1277             }
   1278 
   1279             case 'L': {
   1280                 if (outputFormat != nullptr) {
   1281                     fprintf(stderr,
   1282                             "ERROR: only one -L option allowed. \"%s\" already specified.\n",
   1283                             outputFormat->name().c_str());
   1284                     exit(1);
   1285                 }
   1286                 for (auto& e : kFormats) {
   1287                     if (e.name() == optarg) {
   1288                         outputFormat = &e;
   1289                         break;
   1290                     }
   1291                 }
   1292                 if (outputFormat == nullptr) {
   1293                     fprintf(stderr,
   1294                             "ERROR: unrecognized -L option: \"%s\".\n",
   1295                             optarg);
   1296                     exit(1);
   1297                 }
   1298                 break;
   1299             }
   1300 
   1301             case '?':
   1302             case 'h':
   1303             default: {
   1304                 usage(me);
   1305                 exit(1);
   1306                 break;
   1307             }
   1308         }
   1309     }
   1310 
   1311     if (coordinator.getRootPath().empty()) {
   1312         const char* ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
   1313         if (ANDROID_BUILD_TOP != nullptr) {
   1314             coordinator.setRootPath(ANDROID_BUILD_TOP);
   1315         }
   1316     }
   1317 
   1318     if (outputFormat == nullptr) {
   1319         fprintf(stderr,
   1320             "ERROR: no -L option provided.\n");
   1321         exit(1);
   1322     }
   1323 
   1324     argc -= optind;
   1325     argv += optind;
   1326 
   1327     if (argc == 0) {
   1328         fprintf(stderr, "ERROR: no fqname specified.\n");
   1329         usage(me);
   1330         exit(1);
   1331     }
   1332 
   1333     // Valid options are now in argv[0] .. argv[argc - 1].
   1334 
   1335     switch (outputFormat->mOutputMode) {
   1336         case OutputMode::NEEDS_DIR:
   1337         case OutputMode::NEEDS_FILE: {
   1338             if (outputPath.empty()) {
   1339                 usage(me);
   1340                 exit(1);
   1341             }
   1342 
   1343             if (outputFormat->mOutputMode == OutputMode::NEEDS_DIR) {
   1344                 if (outputPath.back() != '/') {
   1345                     outputPath += "/";
   1346                 }
   1347             }
   1348             break;
   1349         }
   1350         case OutputMode::NEEDS_SRC: {
   1351             if (outputPath.empty()) {
   1352                 outputPath = coordinator.getRootPath();
   1353             }
   1354             if (outputPath.back() != '/') {
   1355                 outputPath += "/";
   1356             }
   1357 
   1358             break;
   1359         }
   1360 
   1361         default:
   1362             outputPath.clear();  // Unused.
   1363             break;
   1364     }
   1365 
   1366     coordinator.setOutputPath(outputPath);
   1367 
   1368     coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
   1369     coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
   1370     coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
   1371     coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
   1372 
   1373     for (int i = 0; i < argc; ++i) {
   1374         FQName fqName;
   1375         if (!FQName::parse(argv[i], &fqName)) {
   1376             fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", argv[i]);
   1377             exit(1);
   1378         }
   1379 
   1380         // Dump extra verbose output
   1381         if (coordinator.isVerbose()) {
   1382             status_t err =
   1383                 dumpDefinedButUnreferencedTypeNames(fqName.getPackageAndVersion(), &coordinator);
   1384             if (err != OK) return err;
   1385         }
   1386 
   1387         if (!outputFormat->validate(fqName, &coordinator, outputFormat->name())) {
   1388             fprintf(stderr,
   1389                     "ERROR: output handler failed.\n");
   1390             exit(1);
   1391         }
   1392 
   1393         status_t err = outputFormat->generate(fqName, &coordinator);
   1394         if (err != OK) exit(1);
   1395 
   1396         err = outputFormat->writeDepFile(fqName, &coordinator);
   1397         if (err != OK) exit(1);
   1398     }
   1399 
   1400     return 0;
   1401 }
   1402