• 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 <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 
501 // Keep the list of libs which are used by VNDK core libs and should be part of
502 // VNDK libs
503 static const std::vector<std::string> vndkLibs = {
504         "android.hardware.audio.common@2.0",
505         "android.hardware.configstore@1.0",
506         "android.hardware.configstore@1.1",
507         "android.hardware.graphics.allocator@2.0",
508         "android.hardware.graphics.allocator@3.0",
509         "android.hardware.graphics.allocator@4.0",
510         "android.hardware.graphics.bufferqueue@1.0",
511         "android.hardware.graphics.bufferqueue@2.0",
512         "android.hardware.media.bufferpool@2.0",
513         "android.hardware.media.omx@1.0",
514         "android.hardware.media@1.0",
515         "android.hardware.memtrack@1.0",
516         "android.hardware.soundtrigger@2.0",
517         "android.hidl.token@1.0",
518         "android.system.suspend@1.0",
519 };
520 
isVndkCoreLib(const FQName & fqName)521 bool isVndkCoreLib(const FQName& fqName) {
522     return std::find(vndkLibs.begin(), vndkLibs.end(), fqName.string()) != vndkLibs.end();
523 }
524 
hasVariantFile(const FQName & fqName,const Coordinator * coordinator,const std::string & fileName,bool * isVariant)525 status_t hasVariantFile(const FQName& fqName, const Coordinator* coordinator,
526                         const std::string& fileName, bool* isVariant) {
527     const auto fileExists = [](const std::string& file) {
528         struct stat buf;
529         return stat(file.c_str(), &buf) == 0;
530     };
531 
532     std::string path;
533     status_t err =
534             coordinator->getFilepath(fqName, Coordinator::Location::PACKAGE_ROOT, fileName, &path);
535     if (err != OK) return err;
536 
537     const bool exists = fileExists(path);
538 
539     if (exists) {
540         coordinator->onFileAccess(path, "r");
541     }
542 
543     *isVariant = exists;
544     return OK;
545 }
546 
isSystemExtPackage(const FQName & fqName,const Coordinator * coordinator,bool * isSystemExt)547 status_t isSystemExtPackage(const FQName& fqName, const Coordinator* coordinator,
548                             bool* isSystemExt) {
549     return hasVariantFile(fqName, coordinator, ".hidl_for_system_ext", isSystemExt);
550 }
551 
isOdmPackage(const FQName & fqName,const Coordinator * coordinator,bool * isOdm)552 status_t isOdmPackage(const FQName& fqName, const Coordinator* coordinator, bool* isOdm) {
553     return hasVariantFile(fqName, coordinator, ".hidl_for_odm", isOdm);
554 }
555 
generateAdapterMainSource(const FQName & packageFQName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)556 static status_t generateAdapterMainSource(const FQName& packageFQName,
557                                           const Coordinator* coordinator,
558                                           const FileGenerator::GetFormatter& getFormatter) {
559     std::vector<FQName> packageInterfaces;
560     status_t err =
561         coordinator->appendPackageInterfacesToVector(packageFQName,
562                                                      &packageInterfaces);
563     if (err != OK) {
564         return err;
565     }
566 
567     // b/146223994: parse all interfaces
568     // - causes files to get read (filling out dep file)
569     // - avoid creating successful output for broken files
570     for (const FQName& fqName : packageInterfaces) {
571         AST* ast = coordinator->parse(fqName);
572         if (ast == nullptr) {
573             fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
574             return UNKNOWN_ERROR;
575         }
576     }
577 
578     Formatter out = getFormatter();
579     if (!out.isValid()) {
580         return UNKNOWN_ERROR;
581     }
582 
583     out << "#include <hidladapter/HidlBinderAdapter.h>\n";
584 
585     for (auto &interface : packageInterfaces) {
586         if (interface.name() == "types") {
587             continue;
588         }
589         AST::generateCppPackageInclude(out, interface, interface.getInterfaceAdapterName());
590     }
591 
592     out << "int main(int argc, char** argv) ";
593     out.block([&] {
594         out << "return ::android::hardware::adapterMain<\n";
595         out.indent();
596         for (auto &interface : packageInterfaces) {
597             if (interface.name() == "types") {
598                 continue;
599             }
600             out << interface.getInterfaceAdapterFqName().cppName();
601 
602             if (&interface != &packageInterfaces.back()) {
603                 out << ",\n";
604             }
605         }
606         out << ">(\"" << packageFQName.string() << "\", argc, argv);\n";
607         out.unindent();
608     }).endl();
609     return OK;
610 }
611 
generateAndroidBpForPackage(const FQName & packageFQName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)612 static status_t generateAndroidBpForPackage(const FQName& packageFQName,
613                                             const Coordinator* coordinator,
614                                             const FileGenerator::GetFormatter& getFormatter) {
615     CHECK(!packageFQName.isFullyQualified() && packageFQName.name().empty());
616 
617     std::vector<FQName> packageInterfaces;
618 
619     status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
620 
621     if (err != OK) {
622         return err;
623     }
624 
625     std::set<FQName> importedPackagesHierarchy;
626     std::vector<const Type *> exportedTypes;
627     AST* typesAST = nullptr;
628 
629     for (const auto& fqName : packageInterfaces) {
630         AST* ast = coordinator->parse(fqName);
631 
632         if (ast == nullptr) {
633             fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
634 
635             return UNKNOWN_ERROR;
636         }
637 
638         if (fqName.name() == "types") {
639             typesAST = ast;
640         }
641 
642         ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
643         ast->appendToExportedTypesVector(&exportedTypes);
644     }
645 
646     bool needsJavaCode = packageNeedsJavaCode(packageInterfaces, typesAST);
647 
648     bool genJavaConstants = needsJavaCode && !exportedTypes.empty();
649 
650     bool isJavaCompatible;
651     err = isPackageJavaCompatible(packageFQName, coordinator, &isJavaCompatible);
652     if (err != OK) return err;
653     bool genJavaLibrary = needsJavaCode && isJavaCompatible;
654 
655     bool isCoreAndroid = isCoreAndroidPackage(packageFQName);
656 
657     bool isVndkCore = isVndkCoreLib(packageFQName);
658     bool isVndkSp = isSystemProcessSupportedPackage(packageFQName);
659 
660     bool isSystemExtHidl;
661     err = isSystemExtPackage(packageFQName, coordinator, &isSystemExtHidl);
662     if (err != OK) return err;
663     bool isSystemExt = isSystemExtHidl || !isCoreAndroid;
664 
665     bool isForOdm;
666     err = isOdmPackage(packageFQName, coordinator, &isForOdm);
667     if (err != OK) return err;
668 
669     std::string packageRoot;
670     err = coordinator->getPackageRoot(packageFQName, &packageRoot);
671     if (err != OK) return err;
672 
673     Formatter out = getFormatter();
674     if (!out.isValid()) {
675         return UNKNOWN_ERROR;
676     }
677 
678     out << "// This file is autogenerated by hidl-gen -Landroidbp.\n\n";
679 
680     out << "hidl_interface ";
681     out.block([&] {
682         out << "name: \"" << makeLibraryName(packageFQName) << "\",\n";
683         if (!coordinator->getOwner().empty()) {
684             out << "owner: \"" << coordinator->getOwner() << "\",\n";
685         }
686         out << "root: \"" << packageRoot << "\",\n";
687         if (isVndkCore || isVndkSp) {
688             out << "vndk: ";
689             out.block([&]() {
690                 out << "enabled: true,\n";
691                 if (isVndkSp) {
692                     out << "support_system_process: true,\n";
693                 }
694             }) << ",\n";
695         }
696         if (isSystemExt) {
697             out << "system_ext_specific: true,\n";
698         }
699         if (isForOdm) {
700             out << "odm_available: true,\n";
701         }
702         (out << "srcs: [\n").indent([&] {
703            for (const auto& fqName : packageInterfaces) {
704                out << "\"" << fqName.name() << ".hal\",\n";
705            }
706         }) << "],\n";
707         if (!importedPackagesHierarchy.empty()) {
708             (out << "interfaces: [\n").indent([&] {
709                for (const auto& fqName : importedPackagesHierarchy) {
710                    out << "\"" << fqName.string() << "\",\n";
711                }
712             }) << "],\n";
713         }
714         // Explicity call this out for developers.
715         out << "gen_java: " << (genJavaLibrary ? "true" : "false") << ",\n";
716         if (genJavaConstants) {
717             out << "gen_java_constants: true,\n";
718         }
719    }).endl();
720 
721     return OK;
722 }
723 
generateAndroidBpImplForPackage(const FQName & packageFQName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)724 static status_t generateAndroidBpImplForPackage(const FQName& packageFQName,
725                                                 const Coordinator* coordinator,
726                                                 const FileGenerator::GetFormatter& getFormatter) {
727     const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
728 
729     std::vector<FQName> packageInterfaces;
730 
731     status_t err =
732         coordinator->appendPackageInterfacesToVector(packageFQName,
733                                                      &packageInterfaces);
734 
735     if (err != OK) {
736         return err;
737     }
738 
739     std::set<FQName> importedPackages;
740 
741     for (const auto &fqName : packageInterfaces) {
742         AST *ast = coordinator->parse(fqName);
743 
744         if (ast == nullptr) {
745             fprintf(stderr,
746                     "ERROR: Could not parse %s. Aborting.\n",
747                     fqName.string().c_str());
748 
749             return UNKNOWN_ERROR;
750         }
751 
752         ast->getImportedPackages(&importedPackages);
753     }
754 
755     Formatter out = getFormatter();
756     if (!out.isValid()) {
757         return UNKNOWN_ERROR;
758     }
759 
760     out << "// FIXME: your file license if you have one\n\n";
761     out << "cc_library_shared {\n";
762     out.indent([&] {
763         out << "// FIXME: this should only be -impl for a passthrough hal.\n"
764             << "// In most cases, to convert this to a binderized implementation, you should:\n"
765             << "// - change '-impl' to '-service' here and make it a cc_binary instead of a\n"
766             << "//   cc_library_shared.\n"
767             << "// - add a *.rc file for this module.\n"
768             << "// - delete HIDL_FETCH_I* functions.\n"
769             << "// - call configureRpcThreadpool and registerAsService on the instance.\n"
770             << "// You may also want to append '-impl/-service' with a specific identifier like\n"
771             << "// '-vendor' or '-<hardware identifier>' etc to distinguish it.\n";
772         out << "name: \"" << libraryName << "\",\n";
773         if (!coordinator->getOwner().empty()) {
774             out << "owner: \"" << coordinator->getOwner() << "\",\n";
775         }
776         out << "relative_install_path: \"hw\",\n";
777         if (coordinator->getOwner().empty()) {
778             out << "// FIXME: this should be 'vendor: true' for modules that will eventually be\n"
779                    "// on AOSP.\n";
780         }
781         out << "proprietary: true,\n";
782         out << "srcs: [\n";
783         out.indent([&] {
784             for (const auto &fqName : packageInterfaces) {
785                 if (fqName.name() == "types") {
786                     continue;
787                 }
788                 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
789             }
790         });
791         out << "],\n"
792             << "shared_libs: [\n";
793         out.indent([&] {
794             out << "\"libhidlbase\",\n"
795                 << "\"libutils\",\n"
796                 << "\"" << makeLibraryName(packageFQName) << "\",\n";
797 
798             for (const auto &importedPackage : importedPackages) {
799                 if (isHidlTransportPackage(importedPackage)) {
800                     continue;
801                 }
802 
803                 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
804             }
805         });
806         out << "],\n";
807     });
808     out << "}\n";
809 
810     return OK;
811 }
812 
validateForSource(const FQName & fqName,const Coordinator * coordinator,const std::string & language)813 bool validateForSource(const FQName& fqName, const Coordinator* coordinator,
814                        const std::string& language) {
815     if (fqName.package().empty()) {
816         fprintf(stderr, "ERROR: Expecting package name\n");
817         return false;
818     }
819 
820     if (fqName.version().empty()) {
821         fprintf(stderr, "ERROR: Expecting package version\n");
822         return false;
823     }
824 
825     const std::string &name = fqName.name();
826     if (!name.empty()) {
827         if (name.find('.') == std::string::npos) {
828             return true;
829         }
830 
831         if (language != "java" || name.find("types.") != 0) {
832             // When generating java sources for "types.hal", output can be
833             // constrained to just one of the top-level types declared
834             // by using the extended syntax
835             // android.hardware.Foo@1.0::types.TopLevelTypeName.
836             // In all other cases (different language, not 'types') the dot
837             // notation in the name is illegal in this context.
838             return false;
839         }
840 
841         return true;
842     }
843 
844     if (language == "java") {
845         bool isJavaCompatible;
846         status_t err = isPackageJavaCompatible(fqName, coordinator, &isJavaCompatible);
847         if (err != OK) return false;
848 
849         if (!isJavaCompatible) {
850             fprintf(stderr,
851                     "ERROR: %s is not Java compatible. The Java backend does NOT support union "
852                     "types. In addition, vectors of arrays are limited to at most one-dimensional "
853                     "arrays and vectors of {vectors,interfaces,memory} are not supported.\n",
854                     fqName.string().c_str());
855             return false;
856         }
857     }
858 
859     return true;
860 }
861 
validateForFormat(const FQName & fqName,const Coordinator * coordinator,const std::string & format)862 bool validateForFormat(const FQName& fqName, const Coordinator* coordinator,
863                        const std::string& format) {
864     CHECK_EQ(format, "format");
865 
866     if (!validateForSource(fqName, coordinator, format)) return false;
867 
868     std::vector<FQName> packageInterfaces;
869 
870     if (fqName.isFullyQualified()) {
871         packageInterfaces.push_back(fqName);
872     } else {
873         status_t err = coordinator->appendPackageInterfacesToVector(fqName, &packageInterfaces);
874         if (err != OK) return err;
875     }
876 
877     bool destroysInformation = false;
878 
879     for (const auto& fqName : packageInterfaces) {
880         AST* ast = coordinator->parse(fqName);
881 
882         if (ast->getUnhandledComments().size() > 0) {
883             destroysInformation = true;
884             for (const auto& i : ast->getUnhandledComments()) {
885                 std::cerr << "Unrecognized comment at " << i->location() << std::endl;
886                 Formatter err(stderr);
887                 err.indent();
888                 i->emit(err);
889                 err.unindent();
890                 err.endl();
891             }
892         }
893     }
894 
895     if (destroysInformation) {
896         std::cerr << "\nhidl-gen does not support comments at these locations, and formatting "
897                      "the file would destroy them. HIDL doc comments need to be multiline comments "
898                      "(/*...*/) before specific elements. This will also cause them to be emitted "
899                      "in output files in the correct locations so that IDE users or people "
900                      "inspecting generated source can see them in the correct location. Formatting "
901                      "the file would destroy these comments.\n";
902         return false;
903     }
904 
905     return true;
906 }
907 
generateExportHeaderForPackage(bool forJava)908 FileGenerator::GenerationFunction generateExportHeaderForPackage(bool forJava) {
909     return [forJava](const FQName& packageFQName, const Coordinator* coordinator,
910                      const FileGenerator::GetFormatter& getFormatter) -> status_t {
911         CHECK(!packageFQName.package().empty() && !packageFQName.version().empty() &&
912               packageFQName.name().empty());
913 
914         std::vector<FQName> packageInterfaces;
915 
916         status_t err = coordinator->appendPackageInterfacesToVector(
917                 packageFQName, &packageInterfaces);
918 
919         if (err != OK) {
920             return err;
921         }
922 
923         std::vector<const Type *> exportedTypes;
924 
925         for (const auto &fqName : packageInterfaces) {
926             AST *ast = coordinator->parse(fqName);
927 
928             if (ast == nullptr) {
929                 fprintf(stderr,
930                         "ERROR: Could not parse %s. Aborting.\n",
931                         fqName.string().c_str());
932 
933                 return UNKNOWN_ERROR;
934             }
935 
936             ast->appendToExportedTypesVector(&exportedTypes);
937         }
938 
939         if (exportedTypes.empty()) {
940             fprintf(stderr,
941                     "ERROR: -Ljava-constants (Android.bp: gen_java_constants) requested for %s, "
942                     "but no types declare @export.",
943                     packageFQName.string().c_str());
944             return UNKNOWN_ERROR;
945         }
946 
947         Formatter out = getFormatter();
948         if (!out.isValid()) {
949             return UNKNOWN_ERROR;
950         }
951 
952         std::string packagePath;
953         err = coordinator->getPackagePath(packageFQName, false /* relative */,
954                                           false /* sanitized */, &packagePath);
955         if (err != OK) return err;
956 
957         out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
958             << "// Source: " << packageFQName.string() << "\n"
959             << "// Location: " << packagePath << "\n\n";
960 
961         std::string guard;
962         if (forJava) {
963             out << "package " << packageFQName.javaPackage() << ";\n\n";
964             out << "public class Constants {\n";
965             out.indent();
966         } else {
967             guard = "HIDL_GENERATED_";
968             guard += StringHelper::Uppercase(packageFQName.tokenName());
969             guard += "_";
970             guard += "EXPORTED_CONSTANTS_H_";
971 
972             out << "#ifndef "
973                 << guard
974                 << "\n#define "
975                 << guard
976                 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
977         }
978 
979         for (const auto &type : exportedTypes) {
980             type->emitExportedHeader(out, forJava);
981         }
982 
983         if (forJava) {
984             out.unindent();
985             out << "}\n";
986         } else {
987             out << "#ifdef __cplusplus\n}\n#endif\n\n#endif  // "
988                 << guard
989                 << "\n";
990         }
991 
992         return OK;
993     };
994 }
995 
generateHashOutput(const FQName & fqName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)996 static status_t generateHashOutput(const FQName& fqName, const Coordinator* coordinator,
997                                    const FileGenerator::GetFormatter& getFormatter) {
998     CHECK(fqName.isFullyQualified());
999 
1000     AST* ast = coordinator->parse(fqName, {} /* parsed */,
1001                                   Coordinator::Enforce::NO_HASH /* enforcement */);
1002 
1003     if (ast == nullptr) {
1004         fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
1005 
1006         return UNKNOWN_ERROR;
1007     }
1008 
1009     Formatter out = getFormatter();
1010     if (!out.isValid()) {
1011         return UNKNOWN_ERROR;
1012     }
1013 
1014     out << Hash::getHash(ast->getFilename()).hexString() << " " << fqName.string() << "\n";
1015 
1016     return OK;
1017 }
1018 
generateFunctionCount(const FQName & fqName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)1019 static status_t generateFunctionCount(const FQName& fqName, const Coordinator* coordinator,
1020                                       const FileGenerator::GetFormatter& getFormatter) {
1021     CHECK(fqName.isFullyQualified());
1022 
1023     AST* ast = coordinator->parse(fqName, {} /* parsed */,
1024                                   Coordinator::Enforce::NO_HASH /* enforcement */);
1025 
1026     if (ast == nullptr) {
1027         fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
1028         return UNKNOWN_ERROR;
1029     }
1030 
1031     const Interface* interface = ast->getInterface();
1032     if (interface == nullptr) {
1033         fprintf(stderr, "ERROR: Function count requires interface: %s.\n", fqName.string().c_str());
1034         return UNKNOWN_ERROR;
1035     }
1036 
1037     Formatter out = getFormatter();
1038     if (!out.isValid()) {
1039         return UNKNOWN_ERROR;
1040     }
1041 
1042     // This is wrong for android.hidl.base@1.0::IBase, but in that case, it doesn't matter.
1043     // This is just the number of APIs that are added.
1044     out << fqName.string() << " " << interface->userDefinedMethods().size() << "\n";
1045 
1046     return OK;
1047 }
1048 
1049 template <typename T>
operator +(const std::vector<T> & lhs,const std::vector<T> & rhs)1050 std::vector<T> operator+(const std::vector<T>& lhs, const std::vector<T>& rhs) {
1051     std::vector<T> ret;
1052     ret.reserve(lhs.size() + rhs.size());
1053     ret.insert(ret.begin(), lhs.begin(), lhs.end());
1054     ret.insert(ret.end(), rhs.begin(), rhs.end());
1055     return ret;
1056 }
1057 
1058 // clang-format off
1059 static const std::vector<FileGenerator> kCppHeaderFormats = {
1060     {
1061         FileGenerator::alwaysGenerate,
__anon226c43a00e02() 1062         [](const FQName& fqName) { return fqName.name() + ".h"; },
1063         astGenerationFunction(&AST::generateInterfaceHeader),
1064     },
1065     {
1066         FileGenerator::alwaysGenerate,
__anon226c43a00f02() 1067         [](const FQName& fqName) {
1068             return fqName.isInterfaceName() ? fqName.getInterfaceHwName() + ".h" : "hwtypes.h";
1069         },
1070         astGenerationFunction(&AST::generateHwBinderHeader),
1071     },
1072     {
1073         FileGenerator::generateForInterfaces,
__anon226c43a01002() 1074         [](const FQName& fqName) { return fqName.getInterfaceStubName() + ".h"; },
1075         astGenerationFunction(&AST::generateStubHeader),
1076     },
1077     {
1078         FileGenerator::generateForInterfaces,
__anon226c43a01102() 1079         [](const FQName& fqName) { return fqName.getInterfaceProxyName() + ".h"; },
1080         astGenerationFunction(&AST::generateProxyHeader),
1081     },
1082     {
1083         FileGenerator::generateForInterfaces,
__anon226c43a01202() 1084         [](const FQName& fqName) { return fqName.getInterfacePassthroughName() + ".h"; },
1085         astGenerationFunction(&AST::generatePassthroughHeader),
1086     },
1087 };
1088 
1089 static const std::vector<FileGenerator> kCppSourceFormats = {
1090     {
1091         FileGenerator::alwaysGenerate,
__anon226c43a01302() 1092         [](const FQName& fqName) {
1093             return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + "All.cpp" : "types.cpp";
1094         },
1095         astGenerationFunction(&AST::generateCppSource),
1096     },
1097 };
1098 
1099 static const std::vector<FileGenerator> kCppImplHeaderFormats = {
1100     {
1101         FileGenerator::generateForInterfaces,
__anon226c43a01402() 1102         [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".h"; },
1103         astGenerationFunction(&AST::generateCppImplHeader),
1104     },
1105 };
1106 
1107 static const std::vector<FileGenerator> kCppImplSourceFormats = {
1108     {
1109         FileGenerator::generateForInterfaces,
__anon226c43a01502() 1110         [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".cpp"; },
1111         astGenerationFunction(&AST::generateCppImplSource),
1112     },
1113 };
1114 
1115 static const std::vector<FileGenerator> kCppAdapterHeaderFormats = {
1116     {
1117         FileGenerator::alwaysGenerate,
__anon226c43a01602() 1118         [](const FQName& fqName) {
1119             return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".h" : "Atypes.h";
1120         },
1121         astGenerationFunction(&AST::generateCppAdapterHeader),
1122     },
1123 };
1124 
1125 static const std::vector<FileGenerator> kCppAdapterSourceFormats = {
1126     {
1127         FileGenerator::alwaysGenerate,
__anon226c43a01702() 1128         [](const FQName& fqName) {
1129             return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".cpp" : "Atypes.cpp";
1130         },
1131         astGenerationFunction(&AST::generateCppAdapterSource),
1132     },
1133 };
1134 
1135 static const std::vector<OutputHandler> kFormats = {
1136     {
1137         "check",
1138         "Parses the interface to see if valid but doesn't write any files.",
1139         OutputMode::NOT_NEEDED,
1140         Coordinator::Location::STANDARD_OUT,
1141         GenerationGranularity::PER_FILE,
1142         validateForSource,
1143         {
1144             {
1145                 FileGenerator::alwaysGenerate,
1146                 nullptr /* filename for fqname */,
1147                 astGenerationFunction(),
1148             },
1149         },
1150     },
1151     {
1152         "c++",
1153         "(internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.",
1154         OutputMode::NEEDS_DIR,
1155         Coordinator::Location::GEN_OUTPUT,
1156         GenerationGranularity::PER_FILE,
1157         validateForSource,
1158         kCppHeaderFormats + kCppSourceFormats,
1159     },
1160     {
1161         "c++-headers",
1162         "(internal) Generates C++ headers for interface files for talking to HIDL interfaces.",
1163         OutputMode::NEEDS_DIR,
1164         Coordinator::Location::GEN_OUTPUT,
1165         GenerationGranularity::PER_FILE,
1166         validateForSource,
1167         kCppHeaderFormats,
1168     },
1169     {
1170         "c++-sources",
1171         "(internal) Generates C++ sources for interface files for talking to HIDL interfaces.",
1172         OutputMode::NEEDS_DIR,
1173         Coordinator::Location::GEN_OUTPUT,
1174         GenerationGranularity::PER_FILE,
1175         validateForSource,
1176         kCppSourceFormats,
1177     },
1178     {
1179         "export-header",
1180         "Generates a header file from @export enumerations to help maintain legacy code.",
1181         OutputMode::NEEDS_FILE,
1182         Coordinator::Location::DIRECT,
1183         GenerationGranularity::PER_PACKAGE,
1184         validateIsPackage,
1185         {singleFileGenerator("", generateExportHeaderForPackage(false /* forJava */))}
1186     },
1187     {
1188         "c++-impl",
1189         "Generates boilerplate implementation of a hidl interface in C++ (for convenience).",
1190         OutputMode::NEEDS_DIR,
1191         Coordinator::Location::DIRECT,
1192         GenerationGranularity::PER_FILE,
1193         validateForSource,
1194         kCppImplHeaderFormats + kCppImplSourceFormats,
1195     },
1196     {
1197         "c++-impl-headers",
1198         "c++-impl but headers only.",
1199         OutputMode::NEEDS_DIR,
1200         Coordinator::Location::DIRECT,
1201         GenerationGranularity::PER_FILE,
1202         validateForSource,
1203         kCppImplHeaderFormats,
1204     },
1205     {
1206         "c++-impl-sources",
1207         "c++-impl but sources only.",
1208         OutputMode::NEEDS_DIR,
1209         Coordinator::Location::DIRECT,
1210         GenerationGranularity::PER_FILE,
1211         validateForSource,
1212         kCppImplSourceFormats,
1213     },
1214     {
1215         "c++-adapter",
1216         "Takes a x.(y+n) interface and mocks an x.y interface.",
1217         OutputMode::NEEDS_DIR,
1218         Coordinator::Location::GEN_OUTPUT,
1219         GenerationGranularity::PER_FILE,
1220         validateForSource,
1221         kCppAdapterHeaderFormats + kCppAdapterSourceFormats,
1222     },
1223     {
1224         "c++-adapter-headers",
1225         "c++-adapter but helper headers only.",
1226         OutputMode::NEEDS_DIR,
1227         Coordinator::Location::GEN_OUTPUT,
1228         GenerationGranularity::PER_FILE,
1229         validateForSource,
1230         kCppAdapterHeaderFormats,
1231     },
1232     {
1233         "c++-adapter-sources",
1234         "c++-adapter but helper sources only.",
1235         OutputMode::NEEDS_DIR,
1236         Coordinator::Location::GEN_OUTPUT,
1237         GenerationGranularity::PER_FILE,
1238         validateForSource,
1239         kCppAdapterSourceFormats,
1240     },
1241     {
1242         "c++-adapter-main",
1243         "c++-adapter but the adapter binary source only.",
1244         OutputMode::NEEDS_DIR,
1245         Coordinator::Location::DIRECT,
1246         GenerationGranularity::PER_PACKAGE,
1247         validateIsPackage,
1248         {singleFileGenerator("main.cpp", generateAdapterMainSource)},
1249     },
1250     {
1251         "java",
1252         "(internal) Generates Java library for talking to HIDL interfaces in Java.",
1253         OutputMode::NEEDS_DIR,
1254         Coordinator::Location::GEN_SANITIZED,
1255         GenerationGranularity::PER_TYPE,
1256         validateForSource,
1257         {
1258             {
1259                 FileGenerator::alwaysGenerate,
__anon226c43a01802() 1260                 [](const FQName& fqName) {
1261                     return StringHelper::LTrim(fqName.name(), "types.") + ".java";
1262                 },
1263                 generateJavaForPackage,
1264             },
1265         }
1266     },
1267     {
1268         "java-impl",
1269         "Generates boilerplate implementation of a hidl interface in Java (for convenience).",
1270         OutputMode::NEEDS_DIR,
1271         Coordinator::Location::DIRECT,
1272         GenerationGranularity::PER_FILE,
1273         validateForSource,
1274         {
1275             {
1276                 FileGenerator::generateForInterfaces,
__anon226c43a01902() 1277                 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".java"; },
1278                 astGenerationFunction(&AST::generateJavaImpl),
1279             },
1280         }
1281     },
1282     {
1283         "java-constants",
1284         "(internal) Like export-header but for Java (always created by -Lmakefile if @export exists).",
1285         OutputMode::NEEDS_DIR,
1286         Coordinator::Location::GEN_SANITIZED,
1287         GenerationGranularity::PER_PACKAGE,
1288         validateIsPackage,
1289         {singleFileGenerator("Constants.java", generateExportHeaderForPackage(true /* forJava */))}
1290     },
1291     {
1292         "vts",
1293         "(internal) Generates vts proto files for use in vtsd.",
1294         OutputMode::NEEDS_DIR,
1295         Coordinator::Location::GEN_OUTPUT,
1296         GenerationGranularity::PER_FILE,
1297         validateForSource,
1298         {
1299             {
1300                 FileGenerator::alwaysGenerate,
__anon226c43a01a02() 1301                 [](const FQName& fqName) {
1302                     return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + ".vts" : "types.vts";
1303                 },
1304                 astGenerationFunction(&AST::generateVts),
1305             },
1306         }
1307     },
1308     {
1309         "makefile",
1310         "(removed) Used to generate makefiles for -Ljava and -Ljava-constants.",
1311         OutputMode::NEEDS_SRC,
1312         Coordinator::Location::PACKAGE_ROOT,
1313         GenerationGranularity::PER_PACKAGE,
__anon226c43a01b02() 1314         [](const FQName &, const Coordinator*, const std::string &) {
1315            fprintf(stderr, "ERROR: makefile output is not supported. Use -Landroidbp for all build file generation.\n");
1316            return false;
1317         },
__anon226c43a01c02() 1318         {},
1319     },
1320     {
1321         "androidbp",
1322         "(internal) Generates Soong bp files for -Lc++-headers, -Lc++-sources, -Ljava, -Ljava-constants, and -Lc++-adapter.",
1323         OutputMode::NEEDS_SRC,
1324         Coordinator::Location::PACKAGE_ROOT,
1325         GenerationGranularity::PER_PACKAGE,
1326         validateIsPackage,
1327         {singleFileGenerator("Android.bp", generateAndroidBpForPackage)},
1328     },
1329     {
1330         "androidbp-impl",
1331         "Generates boilerplate bp files for implementation created with -Lc++-impl.",
1332         OutputMode::NEEDS_DIR,
1333         Coordinator::Location::DIRECT,
1334         GenerationGranularity::PER_PACKAGE,
1335         validateIsPackage,
1336         {singleFileGenerator("Android.bp", generateAndroidBpImplForPackage)},
1337     },
1338     {
1339         "hash",
1340         "Prints hashes of interface in `current.txt` format to standard out.",
1341         OutputMode::NOT_NEEDED,
1342         Coordinator::Location::STANDARD_OUT,
1343         GenerationGranularity::PER_FILE,
1344         validateForSource,
1345         {
1346             {
1347                 FileGenerator::alwaysGenerate,
1348                 nullptr /* file name for fqName */,
1349                 generateHashOutput,
1350             },
1351         }
1352     },
1353     {
1354         "function-count",
1355         "Prints the total number of functions added by the package or interface.",
1356         OutputMode::NOT_NEEDED,
1357         Coordinator::Location::STANDARD_OUT,
1358         GenerationGranularity::PER_FILE,
1359         validateForSource,
1360         {
1361             {
1362                 FileGenerator::generateForInterfaces,
1363                 nullptr /* file name for fqName */,
1364                 generateFunctionCount,
1365             },
1366         }
1367     },
1368     {
1369         "dependencies",
1370         "Prints all depended types.",
1371         OutputMode::NOT_NEEDED,
1372         Coordinator::Location::STANDARD_OUT,
1373         GenerationGranularity::PER_FILE,
1374         validateForSource,
1375         {
1376             {
1377                 FileGenerator::alwaysGenerate,
1378                 nullptr /* file name for fqName */,
1379                 astGenerationFunction(&AST::generateDependencies),
1380             },
1381         },
1382     },
1383     {
1384         "inheritance-hierarchy",
1385         "Prints the hierarchy of inherited types as a JSON object.",
1386         OutputMode::NOT_NEEDED,
1387         Coordinator::Location::STANDARD_OUT,
1388         GenerationGranularity::PER_FILE,
1389         validateForSource,
1390         {
1391             {
1392                 FileGenerator::alwaysGenerate,
1393                 nullptr /* file name for fqName */,
1394                 astGenerationFunction(&AST::generateInheritanceHierarchy),
1395             },
1396         },
1397     },
1398     {
1399         "format",
1400         "Reformats the .hal files",
1401         OutputMode::NEEDS_SRC,
1402         Coordinator::Location::PACKAGE_ROOT,
1403         GenerationGranularity::PER_FILE,
1404         validateForFormat,
1405         {
1406             {
1407                 FileGenerator::alwaysGenerate,
__anon226c43a01d02() 1408                 [](const FQName& fqName) { return fqName.name() + ".hal"; },
1409                 astGenerationFunction(&AST::generateFormattedHidl),
1410             },
1411         }
1412     },
1413 };
1414 // clang-format on
1415 
usage(const char * me)1416 static void usage(const char* me) {
1417     Formatter out(stderr);
1418 
1419     out << "Usage: " << me << " -o <output path> -L <language> [-O <owner>] ";
1420     Coordinator::emitOptionsUsageString(out);
1421     out << " FQNAME...\n\n";
1422 
1423     out << "Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output.\n\n";
1424 
1425     out.indent();
1426     out.indent();
1427 
1428     out << "-h: Prints this menu.\n";
1429     out << "-L <language>: The following options are available:\n";
1430     out.indent([&] {
1431         for (auto& e : kFormats) {
1432             std::stringstream sstream;
1433             sstream.fill(' ');
1434             sstream.width(16);
1435             sstream << std::left << e.name();
1436 
1437             out << sstream.str() << ": " << e.description() << "\n";
1438         }
1439     });
1440     out << "-O <owner>: The owner of the module for -Landroidbp(-impl)?.\n";
1441     out << "-o <output path>: Location to output files.\n";
1442     Coordinator::emitOptionsDetailString(out);
1443 
1444     out.unindent();
1445     out.unindent();
1446 }
1447 
1448 // hidl is intentionally leaky. Turn off LeakSanitizer by default.
__asan_default_options()1449 extern "C" const char *__asan_default_options() {
1450     return "detect_leaks=0";
1451 }
1452 
main(int argc,char ** argv)1453 int main(int argc, char **argv) {
1454     const char *me = argv[0];
1455     if (argc == 1) {
1456         usage(me);
1457         exit(1);
1458     }
1459 
1460     const OutputHandler* outputFormat = nullptr;
1461     Coordinator coordinator;
1462     std::string outputPath;
1463 
1464     coordinator.parseOptions(argc, argv, "ho:O:L:", [&](int res, char* arg) {
1465         switch (res) {
1466             case 'o': {
1467                 if (!outputPath.empty()) {
1468                     fprintf(stderr, "ERROR: -o <output path> can only be specified once.\n");
1469                     exit(1);
1470                 }
1471                 outputPath = arg;
1472                 break;
1473             }
1474 
1475             case 'O': {
1476                 if (!coordinator.getOwner().empty()) {
1477                     fprintf(stderr, "ERROR: -O <owner> can only be specified once.\n");
1478                     exit(1);
1479                 }
1480                 coordinator.setOwner(arg);
1481                 break;
1482             }
1483 
1484             case 'L': {
1485                 if (outputFormat != nullptr) {
1486                     fprintf(stderr,
1487                             "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1488                             outputFormat->name().c_str());
1489                     exit(1);
1490                 }
1491                 for (auto& e : kFormats) {
1492                     if (e.name() == arg) {
1493                         outputFormat = &e;
1494                         break;
1495                     }
1496                 }
1497                 if (outputFormat == nullptr) {
1498                     fprintf(stderr, "ERROR: unrecognized -L option: \"%s\".\n", arg);
1499                     exit(1);
1500                 }
1501                 break;
1502             }
1503 
1504             case '?':
1505             case 'h':
1506             default: {
1507                 usage(me);
1508                 exit(1);
1509                 break;
1510             }
1511         }
1512     });
1513 
1514     if (outputFormat == nullptr) {
1515         fprintf(stderr,
1516             "ERROR: no -L option provided.\n");
1517         exit(1);
1518     }
1519 
1520     argc -= optind;
1521     argv += optind;
1522 
1523     if (argc == 0) {
1524         fprintf(stderr, "ERROR: no fqname specified.\n");
1525         usage(me);
1526         exit(1);
1527     }
1528 
1529     // Valid options are now in argv[0] .. argv[argc - 1].
1530 
1531     switch (outputFormat->mOutputMode) {
1532         case OutputMode::NEEDS_DIR:
1533         case OutputMode::NEEDS_FILE: {
1534             if (outputPath.empty()) {
1535                 usage(me);
1536                 exit(1);
1537             }
1538 
1539             if (outputFormat->mOutputMode == OutputMode::NEEDS_DIR) {
1540                 if (outputPath.back() != '/') {
1541                     outputPath += "/";
1542                 }
1543             }
1544             break;
1545         }
1546         case OutputMode::NEEDS_SRC: {
1547             if (outputPath.empty()) {
1548                 outputPath = coordinator.getRootPath();
1549             }
1550             if (outputPath.back() != '/') {
1551                 outputPath += "/";
1552             }
1553 
1554             break;
1555         }
1556 
1557         default:
1558             outputPath.clear();  // Unused.
1559             break;
1560     }
1561 
1562     coordinator.setOutputPath(outputPath);
1563 
1564     for (int i = 0; i < argc; ++i) {
1565         const char* arg = argv[i];
1566 
1567         FQName fqName;
1568         if (!FQName::parse(arg, &fqName)) {
1569             fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", arg);
1570             exit(1);
1571         }
1572 
1573         if (coordinator.getPackageInterfaceFiles(fqName, nullptr /*fileNames*/) != OK) {
1574             fprintf(stderr, "ERROR: Could not get sources for %s.\n", arg);
1575             exit(1);
1576         }
1577 
1578         // Dump extra verbose output
1579         if (coordinator.isVerbose()) {
1580             status_t err =
1581                 dumpDefinedButUnreferencedTypeNames(fqName.getPackageAndVersion(), &coordinator);
1582             if (err != OK) return err;
1583         }
1584 
1585         if (!outputFormat->validate(fqName, &coordinator, outputFormat->name())) {
1586             fprintf(stderr, "ERROR: Validation failed.\n");
1587             exit(1);
1588         }
1589 
1590         status_t err = outputFormat->generate(fqName, &coordinator);
1591         if (err != OK) exit(1);
1592 
1593         err = outputFormat->writeDepFile(fqName, &coordinator);
1594         if (err != OK) exit(1);
1595     }
1596 
1597     return 0;
1598 }
1599