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