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