• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getFileNameFileGenerator60     std::string getFileName(const FQName& fqName) const {
61         return mFileNameForFqName ? mFileNameForFqName(fqName) : "";
62     }
63 
getOutputFileFileGenerator64     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 
appendOutputFilesFileGenerator73     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 
generateFileGenerator92     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
generateForTypesFileGenerator110     static bool generateForTypes(const FQName& fqName) {
111         const auto names = fqName.names();
112         return names.size() > 0 && names[0] == "types";
113     }
generateForInterfacesFileGenerator114     static bool generateForInterfaces(const FQName& fqName) { return !generateForTypes(fqName); }
alwaysGenerateFileGenerator115     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 
nameOutputHandler131     const std::string& name() const { return mKey; }
descriptionOutputHandler132     const std::string& description() const { return mDescription; }
133 
134     status_t generate(const FQName& fqName, const Coordinator* coordinator) const;
validateOutputHandler135     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
appendPerTypeTargets(const FQName & fqName,const Coordinator * coordinator,std::vector<FQName> * exportedPackageInterfaces)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 
appendTargets(const FQName & fqName,const Coordinator * coordinator,std::vector<FQName> * targets) const175 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 
generate(const FQName & fqName,const Coordinator * coordinator) const210 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 
appendOutputFiles(const FQName & fqName,const Coordinator * coordinator,std::vector<std::string> * outputFiles) const225 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 
writeDepFile(const FQName & fqName,const Coordinator * coordinator) const241 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
astGenerationFunction(void (AST::* generate)(Formatter &)const=nullptr)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
singleFileGenerator(const std::string & fileName,const FileGenerator::GenerationFunction & generationFunction)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 
generateJavaForPackage(Formatter & out,const FQName & fqName,const Coordinator * coordinator)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 
dumpDefinedButUnreferencedTypeNames(const FQName & packageFQName,const Coordinator * coordinator)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 
makeLibraryName(const FQName & packageFQName)336 static std::string makeLibraryName(const FQName &packageFQName) {
337     return packageFQName.string();
338 }
339 
isPackageJavaCompatible(const FQName & packageFQName,const Coordinator * coordinator,bool * compatible)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 
packageNeedsJavaCode(const std::vector<FQName> & packageInterfaces,AST * typesAST)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 
validateIsPackage(const FQName & fqName,const Coordinator *,const std::string &)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 
isHidlTransportPackage(const FQName & fqName)450 bool isHidlTransportPackage(const FQName& fqName) {
451     return fqName.package() == gIBaseFqName.package() ||
452            fqName.package() == gIManagerFqName.package();
453 }
454 
isSystemProcessSupportedPackage(const FQName & fqName)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@1.0" ||
459            fqName.string() == "android.hardware.graphics.common@1.1" ||
460            fqName.string() == "android.hardware.graphics.mapper@2.0" ||
461            fqName.string() == "android.hardware.graphics.mapper@2.1" ||
462            fqName.string() == "android.hardware.renderscript@1.0" ||
463            fqName.string() == "android.hidl.memory.token@1.0" ||
464            fqName.string() == "android.hidl.memory@1.0";
465 }
466 
isSystemPackage(const FQName & package)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
isTestPackage(const FQName & fqName,const Coordinator * coordinator,bool * isTestPackage)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 
generateAdapterMainSource(Formatter & out,const FQName & packageFQName,const Coordinator * coordinator)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 
generateAndroidBpForPackage(Formatter & out,const FQName & packageFQName,const Coordinator * coordinator)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 
generateAndroidBpImplForPackage(Formatter & out,const FQName & packageFQName,const Coordinator * coordinator)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 
validateForSource(const FQName & fqName,const Coordinator * coordinator,const std::string & language)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@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 
generateExportHeaderForPackage(bool forJava)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 
generateHashOutput(Formatter & out,const FQName & fqName,const Coordinator * coordinator)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>
operator +(const std::vector<T> & lhs,const std::vector<T> & rhs)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,
__anonb03561f60f02() 901         [](const FQName& fqName) { return fqName.name() + ".h"; },
902         astGenerationFunction(&AST::generateInterfaceHeader),
903     },
904     {
905         FileGenerator::alwaysGenerate,
__anonb03561f61002() 906         [](const FQName& fqName) {
907             return fqName.isInterfaceName() ? fqName.getInterfaceHwName() + ".h" : "hwtypes.h";
908         },
909         astGenerationFunction(&AST::generateHwBinderHeader),
910     },
911     {
912         FileGenerator::generateForInterfaces,
__anonb03561f61102() 913         [](const FQName& fqName) { return fqName.getInterfaceStubName() + ".h"; },
914         astGenerationFunction(&AST::generateStubHeader),
915     },
916     {
917         FileGenerator::generateForInterfaces,
__anonb03561f61202() 918         [](const FQName& fqName) { return fqName.getInterfaceProxyName() + ".h"; },
919         astGenerationFunction(&AST::generateProxyHeader),
920     },
921     {
922         FileGenerator::generateForInterfaces,
__anonb03561f61302() 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,
__anonb03561f61402() 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,
__anonb03561f61502() 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,
__anonb03561f61602() 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,
__anonb03561f61702() 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,
__anonb03561f61802() 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,
__anonb03561f61902() 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,
__anonb03561f61a02() 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,
__anonb03561f61b02() 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         },
__anonb03561f61c02() 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 
usage(const char * me)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.
__asan_default_options()1203 extern "C" const char *__asan_default_options() {
1204     return "detect_leaks=0";
1205 }
1206 
main(int argc,char ** argv)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