• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "AST.h"
18 #include "Coordinator.h"
19 #include "Scope.h"
20 
21 #include <hidl-hash/Hash.h>
22 #include <hidl-util/Formatter.h>
23 #include <hidl-util/FQName.h>
24 #include <hidl-util/StringHelper.h>
25 #include <android-base/logging.h>
26 #include <set>
27 #include <stdio.h>
28 #include <string>
29 #include <unistd.h>
30 #include <vector>
31 
32 using namespace android;
33 
34 struct OutputHandler {
35     std::string mKey;
36     std::string mDescription;
37     enum OutputMode {
38         NEEDS_DIR,
39         NEEDS_FILE,
40         NEEDS_SRC, // for changes inside the source tree itself
41         NOT_NEEDED
42     } mOutputMode;
43 
nameOutputHandler44     const std::string& name() { return mKey; }
descriptionOutputHandler45     const std::string& description() { return mDescription; }
46 
47     using ValidationFunction = std::function<bool(const FQName &, const std::string &language)>;
48     using GenerationFunction = std::function<status_t(const FQName &fqName,
49                                                       const char *hidl_gen,
50                                                       Coordinator *coordinator,
51                                                       const std::string &outputDir)>;
52 
53     ValidationFunction validate;
54     GenerationFunction generate;
55 };
56 
57 static bool generateForTest = false;
58 
generateSourcesForFile(const FQName & fqName,const char *,Coordinator * coordinator,const std::string & outputDir,const std::string & lang)59 static status_t generateSourcesForFile(
60         const FQName &fqName,
61         const char *,
62         Coordinator *coordinator,
63         const std::string &outputDir,
64         const std::string &lang) {
65     CHECK(fqName.isFullyQualified());
66 
67     AST *ast;
68     std::string limitToType;
69 
70     if (fqName.name().find("types.") == 0) {
71         CHECK(lang == "java");  // Already verified in validate().
72 
73         limitToType = fqName.name().substr(strlen("types."));
74 
75         FQName typesName = fqName.getTypesForPackage();
76         ast = coordinator->parse(typesName);
77     } else {
78         ast = coordinator->parse(fqName);
79     }
80 
81     if (ast == NULL) {
82         fprintf(stderr,
83                 "ERROR: Could not parse %s. Aborting.\n",
84                 fqName.string().c_str());
85 
86         return UNKNOWN_ERROR;
87     }
88 
89     if (lang == "check") {
90         return OK; // only parsing, not generating
91     }
92     if (lang == "c++") {
93         return ast->generateCpp(outputDir);
94     }
95     if (lang == "c++-headers") {
96         return ast->generateCppHeaders(outputDir);
97     }
98     if (lang == "c++-sources") {
99         return ast->generateCppSources(outputDir);
100     }
101     if (lang == "c++-impl") {
102         return ast->generateCppImpl(outputDir);
103     }
104     if (lang == "c++-impl-headers") {
105         return ast->generateStubImplHeader(outputDir);
106     }
107     if (lang == "c++-impl-sources") {
108         return ast->generateStubImplSource(outputDir);
109     }
110     if (lang == "java") {
111         return ast->generateJava(outputDir, limitToType);
112     }
113     if (lang == "vts") {
114         return ast->generateVts(outputDir);
115     }
116     // Unknown language.
117     return UNKNOWN_ERROR;
118 }
119 
generateSourcesForPackage(const FQName & packageFQName,const char * hidl_gen,Coordinator * coordinator,const std::string & outputDir,const std::string & lang)120 static status_t generateSourcesForPackage(
121         const FQName &packageFQName,
122         const char *hidl_gen,
123         Coordinator *coordinator,
124         const std::string &outputDir,
125         const std::string &lang) {
126     CHECK(packageFQName.isValid() &&
127         !packageFQName.isFullyQualified() &&
128         packageFQName.name().empty());
129 
130     std::vector<FQName> packageInterfaces;
131 
132     status_t err =
133         coordinator->appendPackageInterfacesToVector(packageFQName,
134                                                      &packageInterfaces);
135 
136     if (err != OK) {
137         return err;
138     }
139 
140     for (const auto &fqName : packageInterfaces) {
141         err = generateSourcesForFile(
142                 fqName, hidl_gen, coordinator, outputDir, lang);
143         if (err != OK) {
144             return err;
145         }
146     }
147 
148     return OK;
149 }
150 
generationFunctionForFileOrPackage(const std::string & language)151 OutputHandler::GenerationFunction generationFunctionForFileOrPackage(const std::string &language) {
152     return [language](const FQName &fqName,
153               const char *hidl_gen, Coordinator *coordinator,
154               const std::string &outputDir) -> status_t {
155         if (fqName.isFullyQualified()) {
156                     return generateSourcesForFile(fqName,
157                                                   hidl_gen,
158                                                   coordinator,
159                                                   outputDir,
160                                                   language);
161         } else {
162                     return generateSourcesForPackage(fqName,
163                                                      hidl_gen,
164                                                      coordinator,
165                                                      outputDir,
166                                                      language);
167         }
168     };
169 }
170 
makeLibraryName(const FQName & packageFQName)171 static std::string makeLibraryName(const FQName &packageFQName) {
172     return packageFQName.string();
173 }
174 
makeJavaLibraryName(const FQName & packageFQName)175 static std::string makeJavaLibraryName(const FQName &packageFQName) {
176     std::string out;
177     out = packageFQName.package();
178     out += "-V";
179     out += packageFQName.version();
180     return out;
181 }
182 
generatePackagePathsSection(Formatter & out,Coordinator * coordinator,const FQName & packageFQName,const std::set<FQName> & importedPackages,bool forMakefiles=false)183 static void generatePackagePathsSection(
184         Formatter &out,
185         Coordinator *coordinator,
186         const FQName &packageFQName,
187         const std::set<FQName> &importedPackages,
188         bool forMakefiles = false) {
189     std::set<std::string> options{};
190     for (const auto &interface : importedPackages) {
191         options.insert(coordinator->getPackageRootOption(interface));
192     }
193     options.insert(coordinator->getPackageRootOption(packageFQName));
194     options.insert(coordinator->getPackageRootOption(gIBaseFqName));
195     for (const auto &option : options) {
196         out << "-r"
197             << option
198             << " ";
199         if (forMakefiles) {
200             out << "\\\n";
201         }
202     }
203 }
204 
generateMakefileSectionForType(Formatter & out,Coordinator * coordinator,const FQName & packageFQName,const FQName & fqName,const std::set<FQName> & importedPackages,const char * typeName)205 static void generateMakefileSectionForType(
206         Formatter &out,
207         Coordinator *coordinator,
208         const FQName &packageFQName,
209         const FQName &fqName,
210         const std::set<FQName> &importedPackages,
211         const char *typeName) {
212     out << "\n"
213         << "\n#"
214         << "\n# Build " << fqName.name() << ".hal";
215 
216     if (typeName != nullptr) {
217         out << " (" << typeName << ")";
218     }
219 
220     out << "\n#"
221         << "\nGEN := $(intermediates)/"
222         << coordinator->convertPackageRootToPath(packageFQName)
223         << coordinator->getPackagePath(packageFQName, true /* relative */,
224                 true /* sanitized */);
225     if (typeName == nullptr) {
226         out << fqName.name() << ".java";
227     } else {
228         out << typeName << ".java";
229     }
230 
231     out << "\n$(GEN): $(HIDL)";
232     out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
233     out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
234         << fqName.name() << ".hal";
235 
236     {
237         AST *ast = coordinator->parse(fqName);
238         CHECK(ast != nullptr);
239         const std::set<FQName>& refs = ast->getImportedNames();
240         for (auto depFQName : refs) {
241             // If the package of depFQName is the same as this fqName's package,
242             // then add it explicitly as a .hal dependency within the same
243             // package.
244             if (fqName.package() == depFQName.package() &&
245                 fqName.version() == depFQName.version()) {
246                     // PRIVATE_DEPS is not actually being used in the
247                     // auto-generated file, but is necessary if the build rule
248                     // ever needs to use the dependency information, since the
249                     // built-in Make variables are not supported in the Android
250                     // build system.
251                     out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
252                         << depFQName.name() << ".hal";
253                     // This is the actual dependency.
254                     out << "\n$(GEN): $(LOCAL_PATH)/"
255                         << depFQName.name() << ".hal";
256             }
257         }
258     }
259 
260     out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
261         << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
262     out.indent();
263     out.indent();
264     out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
265         << "\n-Ljava \\\n";
266 
267     generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
268 
269     out << packageFQName.string()
270         << "::"
271         << fqName.name();
272 
273     if (typeName != nullptr) {
274         out << "." << typeName;
275     }
276 
277     out << "\n";
278 
279     out.unindent();
280     out.unindent();
281 
282     out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
283     out << "\n\t$(transform-generated-source)";
284     out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
285 }
286 
generateMakefileSection(Formatter & out,Coordinator * coordinator,const FQName & packageFQName,const std::vector<FQName> & packageInterfaces,const std::set<FQName> & importedPackages,AST * typesAST)287 static void generateMakefileSection(
288         Formatter &out,
289         Coordinator *coordinator,
290         const FQName &packageFQName,
291         const std::vector<FQName> &packageInterfaces,
292         const std::set<FQName> &importedPackages,
293         AST *typesAST) {
294     for (const auto &fqName : packageInterfaces) {
295         if (fqName.name() == "types") {
296             CHECK(typesAST != nullptr);
297 
298             Scope* rootScope = typesAST->getRootScope();
299 
300             std::vector<NamedType *> subTypes = rootScope->getSubTypes();
301             std::sort(
302                     subTypes.begin(),
303                     subTypes.end(),
304                     [](const NamedType *a, const NamedType *b) -> bool {
305                         return a->fqName() < b->fqName();
306                     });
307 
308             for (const auto &type : subTypes) {
309                 if (type->isTypeDef()) {
310                     continue;
311                 }
312 
313                 generateMakefileSectionForType(
314                         out,
315                         coordinator,
316                         packageFQName,
317                         fqName,
318                         importedPackages,
319                         type->localName().c_str());
320             }
321 
322             continue;
323         }
324 
325         generateMakefileSectionForType(
326                 out,
327                 coordinator,
328                 packageFQName,
329                 fqName,
330                 importedPackages,
331                 nullptr /* typeName */);
332     }
333 }
334 
isPackageJavaCompatible(const FQName & packageFQName,Coordinator * coordinator,bool * compatible)335 static status_t isPackageJavaCompatible(
336         const FQName &packageFQName,
337         Coordinator *coordinator,
338         bool *compatible) {
339     std::vector<FQName> todo;
340     status_t err =
341         coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
342 
343     if (err != OK) {
344         return err;
345     }
346 
347     std::set<FQName> seen;
348     for (const auto &iface : todo) {
349         seen.insert(iface);
350     }
351 
352     // Form the transitive closure of all imported interfaces (and types.hal-s)
353     // If any one of them is not java compatible, this package isn't either.
354     while (!todo.empty()) {
355         const FQName fqName = todo.back();
356         todo.pop_back();
357 
358         AST *ast = coordinator->parse(fqName);
359 
360         if (ast == nullptr) {
361             return UNKNOWN_ERROR;
362         }
363 
364         if (!ast->isJavaCompatible()) {
365             *compatible = false;
366             return OK;
367         }
368 
369         std::set<FQName> importedPackages;
370         ast->getImportedPackages(&importedPackages);
371 
372         for (const auto &package : importedPackages) {
373             std::vector<FQName> packageInterfaces;
374             status_t err = coordinator->appendPackageInterfacesToVector(
375                     package, &packageInterfaces);
376 
377             if (err != OK) {
378                 return err;
379             }
380 
381             for (const auto &iface : packageInterfaces) {
382                 if (seen.find(iface) != seen.end()) {
383                     continue;
384                 }
385 
386                 todo.push_back(iface);
387                 seen.insert(iface);
388             }
389         }
390     }
391 
392     *compatible = true;
393     return OK;
394 }
395 
packageNeedsJavaCode(const std::vector<FQName> & packageInterfaces,AST * typesAST)396 static bool packageNeedsJavaCode(
397         const std::vector<FQName> &packageInterfaces, AST *typesAST) {
398     // If there is more than just a types.hal file to this package we'll
399     // definitely need to generate Java code.
400     if (packageInterfaces.size() > 1
401             || packageInterfaces[0].name() != "types") {
402         return true;
403     }
404 
405     CHECK(typesAST != nullptr);
406 
407     // We'll have to generate Java code if types.hal contains any non-typedef
408     // type declarations.
409 
410     Scope* rootScope = typesAST->getRootScope();
411     std::vector<NamedType *> subTypes = rootScope->getSubTypes();
412 
413     for (const auto &subType : subTypes) {
414         if (!subType->isTypeDef()) {
415             return true;
416         }
417     }
418 
419     return false;
420 }
421 
generateMakefileSectionForJavaConstants(Formatter & out,Coordinator * coordinator,const FQName & packageFQName,const std::vector<FQName> & packageInterfaces,const std::set<FQName> & importedPackages)422 static void generateMakefileSectionForJavaConstants(
423         Formatter &out,
424         Coordinator *coordinator,
425         const FQName &packageFQName,
426         const std::vector<FQName> &packageInterfaces,
427         const std::set<FQName> &importedPackages) {
428     out << "\n#"
429         << "\nGEN := $(intermediates)/"
430         << coordinator->convertPackageRootToPath(packageFQName)
431         << coordinator->getPackagePath(packageFQName, true /* relative */, true /* sanitized */)
432         << "Constants.java";
433 
434     out << "\n$(GEN): $(HIDL)\n";
435     for (const auto &iface : packageInterfaces) {
436         out << "$(GEN): $(LOCAL_PATH)/" << iface.name() << ".hal\n";
437     }
438     out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
439     out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
440         << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
441     out.indent();
442     out.indent();
443     out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
444         << "\n-Ljava-constants \\\n";
445 
446     generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
447 
448     out << packageFQName.string();
449     out << "\n";
450 
451     out.unindent();
452     out.unindent();
453 
454     out << "\n$(GEN):";
455     out << "\n\t$(transform-generated-source)";
456     out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
457 }
458 
generateMakefileForPackage(const FQName & packageFQName,const char * hidl_gen,Coordinator * coordinator,const std::string & outputPath)459 static status_t generateMakefileForPackage(
460         const FQName &packageFQName,
461         const char *hidl_gen,
462         Coordinator *coordinator,
463         const std::string &outputPath) {
464 
465     CHECK(packageFQName.isValid() &&
466           !packageFQName.isFullyQualified() &&
467           packageFQName.name().empty());
468 
469     std::vector<FQName> packageInterfaces;
470 
471     status_t err =
472         coordinator->appendPackageInterfacesToVector(packageFQName,
473                                                      &packageInterfaces);
474 
475     if (err != OK) {
476         return err;
477     }
478 
479     std::set<FQName> importedPackages;
480     AST *typesAST = nullptr;
481     std::vector<const Type *> exportedTypes;
482 
483     for (const auto &fqName : packageInterfaces) {
484         AST *ast = coordinator->parse(fqName);
485 
486         if (ast == NULL) {
487             fprintf(stderr,
488                     "ERROR: Could not parse %s. Aborting.\n",
489                     fqName.string().c_str());
490 
491             return UNKNOWN_ERROR;
492         }
493 
494         if (fqName.name() == "types") {
495             typesAST = ast;
496         }
497 
498         ast->getImportedPackagesHierarchy(&importedPackages);
499         ast->appendToExportedTypesVector(&exportedTypes);
500     }
501 
502     bool packageIsJavaCompatible;
503     err = isPackageJavaCompatible(
504             packageFQName, coordinator, &packageIsJavaCompatible);
505 
506     if (err != OK) {
507         return err;
508     }
509 
510     bool haveJavaConstants = !exportedTypes.empty();
511 
512     if (!packageIsJavaCompatible && !haveJavaConstants) {
513         // TODO(b/33420795)
514         fprintf(stderr,
515                 "WARNING: %s is not java compatible. No java makefile created.\n",
516                 packageFQName.string().c_str());
517         return OK;
518     }
519 
520     if (!packageNeedsJavaCode(packageInterfaces, typesAST)) {
521         return OK;
522     }
523 
524     std::string path = outputPath;
525     path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
526     path.append("Android.mk");
527 
528     CHECK(Coordinator::MakeParentHierarchy(path));
529     FILE *file = fopen(path.c_str(), "w");
530 
531     if (file == NULL) {
532         return -errno;
533     }
534 
535     const std::string libraryName = makeJavaLibraryName(packageFQName);
536 
537     Formatter out(file);
538 
539     out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
540     out << "LOCAL_PATH := $(call my-dir)\n";
541 
542     enum LibraryStyle {
543         LIBRARY_STYLE_REGULAR,
544         LIBRARY_STYLE_STATIC,
545         LIBRARY_STYLE_END,
546     };
547 
548     for (int style = LIBRARY_STYLE_REGULAR;
549             (packageIsJavaCompatible && style != LIBRARY_STYLE_END);
550             ++style) {
551         const std::string staticSuffix =
552             (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
553 
554         out << "\n"
555             << "########################################"
556             << "########################################\n\n";
557 
558         out << "include $(CLEAR_VARS)\n"
559             << "LOCAL_MODULE := "
560             << libraryName
561             << "-java"
562             << staticSuffix
563             << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
564             << "intermediates := $(call local-generated-sources-dir, COMMON)"
565             << "\n\n"
566             << "HIDL := $(HOST_OUT_EXECUTABLES)/"
567             << hidl_gen
568             << "$(HOST_EXECUTABLE_SUFFIX)";
569 
570         if (!importedPackages.empty()) {
571             out << "\n"
572                 << "\nLOCAL_"
573                 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
574                 << "JAVA_LIBRARIES := \\";
575 
576             out.indent();
577             for (const auto &importedPackage : importedPackages) {
578                 out << "\n"
579                     << makeJavaLibraryName(importedPackage)
580                     << "-java"
581                     << staticSuffix
582                     << " \\";
583             }
584             out << "\n";
585             out.unindent();
586         }
587 
588         generateMakefileSection(
589                 out,
590                 coordinator,
591                 packageFQName,
592                 packageInterfaces,
593                 importedPackages,
594                 typesAST);
595 
596         out << "\ninclude $(BUILD_"
597             << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
598             << "JAVA_LIBRARY)\n\n";
599     }
600 
601     if (haveJavaConstants) {
602         out << "\n"
603             << "########################################"
604             << "########################################\n\n";
605 
606         out << "include $(CLEAR_VARS)\n"
607             << "LOCAL_MODULE := "
608             << libraryName
609             << "-java-constants"
610             << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
611             << "intermediates := $(call local-generated-sources-dir, COMMON)"
612             << "\n\n"
613             << "HIDL := $(HOST_OUT_EXECUTABLES)/"
614             << hidl_gen
615             << "$(HOST_EXECUTABLE_SUFFIX)";
616 
617         generateMakefileSectionForJavaConstants(
618                 out, coordinator, packageFQName, packageInterfaces, importedPackages);
619 
620         out << "\n# Avoid dependency cycle of framework.jar -> this-library "
621             << "-> framework.jar\n"
622             << "LOCAL_NO_STANDARD_LIBRARIES := true\n"
623             << "LOCAL_JAVA_LIBRARIES := core-oj\n\n"
624             << "include $(BUILD_STATIC_JAVA_LIBRARY)\n\n";
625     }
626 
627     out << "\n\n"
628         << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
629 
630     return OK;
631 }
632 
validateIsPackage(const FQName & fqName,const std::string &)633 bool validateIsPackage(
634         const FQName &fqName, const std::string & /* language */) {
635     if (fqName.package().empty()) {
636         fprintf(stderr, "ERROR: Expecting package name\n");
637         return false;
638     }
639 
640     if (fqName.version().empty()) {
641         fprintf(stderr, "ERROR: Expecting package version\n");
642         return false;
643     }
644 
645     if (!fqName.name().empty()) {
646         fprintf(stderr,
647                 "ERROR: Expecting only package name and version.\n");
648         return false;
649     }
650 
651     return true;
652 }
653 
isHidlTransportPackage(const FQName & fqName)654 bool isHidlTransportPackage(const FQName& fqName) {
655     return fqName.package() == gIBasePackageFqName.string() ||
656            fqName.package() == gIManagerPackageFqName.string();
657 }
658 
isSystemProcessSupportedPackage(const FQName & fqName)659 bool isSystemProcessSupportedPackage(const FQName& fqName) {
660     // Technically, so is hidl IBase + IServiceManager, but
661     // these are part of libhidltransport.
662     return fqName.string() == "android.hardware.graphics.allocator@2.0" ||
663            fqName.string() == "android.hardware.graphics.common@1.0" ||
664            fqName.string() == "android.hardware.graphics.mapper@2.0" ||
665            fqName.string() == "android.hardware.renderscript@1.0" ||
666            fqName.string() == "android.hidl.memory@1.0";
667 }
668 
isSystemPackage(const FQName & package)669 bool isSystemPackage(const FQName &package) {
670     return package.inPackage("android.hidl") ||
671            package.inPackage("android.system") ||
672            package.inPackage("android.frameworks") ||
673            package.inPackage("android.hardware");
674 }
675 
generateAndroidBpGenSection(Formatter & out,const FQName & packageFQName,const char * hidl_gen,Coordinator * coordinator,const std::string & halFilegroupName,const std::string & genName,const char * language,const std::vector<FQName> & packageInterfaces,const std::set<FQName> & importedPackages,const std::function<void (Formatter &,const FQName)> outputFn)676 static void generateAndroidBpGenSection(
677         Formatter &out,
678         const FQName &packageFQName,
679         const char *hidl_gen,
680         Coordinator *coordinator,
681         const std::string &halFilegroupName,
682         const std::string &genName,
683         const char *language,
684         const std::vector<FQName> &packageInterfaces,
685         const std::set<FQName> &importedPackages,
686         const std::function<void(Formatter&, const FQName)> outputFn) {
687 
688     out << "genrule {\n";
689     out.indent();
690     out << "name: \"" << genName << "\",\n"
691         << "tools: [\"" << hidl_gen << "\"],\n";
692 
693     out << "cmd: \"$(location " << hidl_gen << ") -o $(genDir)"
694         << " -L" << language << " ";
695 
696     generatePackagePathsSection(out, coordinator, packageFQName, importedPackages);
697 
698     out << packageFQName.string() << "\",\n";
699 
700     out << "srcs: [\n";
701     out.indent();
702     out << "\":" << halFilegroupName << "\",\n";
703     out.unindent();
704     out << "],\n";
705 
706     out << "out: [\n";
707     out.indent();
708     for (const auto &fqName : packageInterfaces) {
709         outputFn(out, fqName);
710     }
711     out.unindent();
712     out << "],\n";
713 
714     out.unindent();
715     out << "}\n\n";
716 }
717 
generateAndroidBpDependencyList(Formatter & out,const std::set<FQName> & importedPackagesHierarchy,bool generateVendor)718 static void generateAndroidBpDependencyList(
719         Formatter &out,
720         const std::set<FQName> &importedPackagesHierarchy,
721         bool generateVendor) {
722     for (const auto &importedPackage : importedPackagesHierarchy) {
723         if (isHidlTransportPackage(importedPackage)) {
724             continue;
725         }
726 
727         out << "\"" << makeLibraryName(importedPackage);
728         if (generateVendor && !isSystemPackage(importedPackage)) {
729             out << "_vendor";
730         }
731         out << "\",\n";
732     }
733 }
734 
generateAndroidBpLibSection(Formatter & out,bool generateVendor,const FQName & packageFQName,const std::string & libraryName,const std::string & genSourceName,const std::string & genHeaderName,const std::set<FQName> & importedPackagesHierarchy)735 static void generateAndroidBpLibSection(
736         Formatter &out,
737         bool generateVendor,
738         const FQName &packageFQName,
739         const std::string &libraryName,
740         const std::string &genSourceName,
741         const std::string &genHeaderName,
742         const std::set<FQName> &importedPackagesHierarchy) {
743 
744     // C++ library definition
745     out << "cc_library {\n";
746     out.indent();
747     out << "name: \"" << libraryName << (generateVendor ? "_vendor" : "") << "\",\n"
748         << "defaults: [\"hidl-module-defaults\"],\n"
749         << "generated_sources: [\"" << genSourceName << "\"],\n"
750         << "generated_headers: [\"" << genHeaderName << "\"],\n"
751         << "export_generated_headers: [\"" << genHeaderName << "\"],\n";
752 
753     if (generateVendor) {
754         out << "vendor: true,\n";
755     } else {
756         out << "vendor_available: true,\n";
757         if (!generateForTest) {
758             out << "vndk: ";
759             out.block([&]() {
760                 out << "enabled: true,\n";
761                 if (isSystemProcessSupportedPackage(packageFQName)) {
762                     out << "support_system_process: true,\n";
763                 }
764             }) << ",\n";
765         }
766     }
767     out << "shared_libs: [\n";
768 
769     out.indent();
770     out << "\"libhidlbase\",\n"
771         << "\"libhidltransport\",\n"
772         << "\"libhwbinder\",\n"
773         << "\"liblog\",\n"
774         << "\"libutils\",\n"
775         << "\"libcutils\",\n";
776     generateAndroidBpDependencyList(out, importedPackagesHierarchy, generateVendor);
777     out.unindent();
778 
779     out << "],\n";
780 
781     out << "export_shared_lib_headers: [\n";
782     out.indent();
783     out << "\"libhidlbase\",\n"
784         << "\"libhidltransport\",\n"
785         << "\"libhwbinder\",\n"
786         << "\"libutils\",\n";
787     generateAndroidBpDependencyList(out, importedPackagesHierarchy, generateVendor);
788     out.unindent();
789     out << "],\n";
790     out.unindent();
791 
792     out << "}\n";
793 }
794 
generateAndroidBpForPackage(const FQName & packageFQName,const char * hidl_gen,Coordinator * coordinator,const std::string & outputPath)795 static status_t generateAndroidBpForPackage(
796         const FQName &packageFQName,
797         const char *hidl_gen,
798         Coordinator *coordinator,
799         const std::string &outputPath) {
800 
801     CHECK(packageFQName.isValid() &&
802           !packageFQName.isFullyQualified() &&
803           packageFQName.name().empty());
804 
805     std::vector<FQName> packageInterfaces;
806 
807     status_t err =
808         coordinator->appendPackageInterfacesToVector(packageFQName,
809                                                      &packageInterfaces);
810 
811     if (err != OK) {
812         return err;
813     }
814 
815     std::set<FQName> importedPackagesHierarchy;
816     AST *typesAST = nullptr;
817 
818     for (const auto &fqName : packageInterfaces) {
819         AST *ast = coordinator->parse(fqName);
820 
821         if (ast == NULL) {
822             fprintf(stderr,
823                     "ERROR: Could not parse %s. Aborting.\n",
824                     fqName.string().c_str());
825 
826             return UNKNOWN_ERROR;
827         }
828 
829         if (fqName.name() == "types") {
830             typesAST = ast;
831         }
832 
833         ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
834     }
835 
836     std::string path = outputPath;
837     path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
838     path.append("Android.bp");
839 
840     CHECK(Coordinator::MakeParentHierarchy(path));
841     FILE *file = fopen(path.c_str(), "w");
842 
843     if (file == NULL) {
844         return -errno;
845     }
846 
847     const std::string libraryName = makeLibraryName(packageFQName);
848     const std::string halFilegroupName = libraryName + "_hal";
849     const std::string genSourceName = libraryName + "_genc++";
850     const std::string genHeaderName = libraryName + "_genc++_headers";
851     const std::string pathPrefix =
852         coordinator->convertPackageRootToPath(packageFQName) +
853         coordinator->getPackagePath(packageFQName, true /* relative */);
854 
855     Formatter out(file);
856 
857     out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
858 
859     // Rule to generate .hal filegroup
860     out << "filegroup {\n";
861     out.indent();
862     out << "name: \"" << halFilegroupName << "\",\n";
863     out << "srcs: [\n";
864     out.indent();
865     for (const auto &fqName : packageInterfaces) {
866       out << "\"" << fqName.name() << ".hal\",\n";
867     }
868     out.unindent();
869     out << "],\n";
870     out.unindent();
871     out << "}\n\n";
872 
873     // Rule to generate the C++ source files
874     generateAndroidBpGenSection(
875             out,
876             packageFQName,
877             hidl_gen,
878             coordinator,
879             halFilegroupName,
880             genSourceName,
881             "c++-sources",
882             packageInterfaces,
883             importedPackagesHierarchy,
884             [&pathPrefix](Formatter &out, const FQName &fqName) {
885                 if (fqName.name() == "types") {
886                     out << "\"" << pathPrefix << "types.cpp\",\n";
887                 } else {
888                     out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
889                 }
890             });
891 
892     // Rule to generate the C++ header files
893     generateAndroidBpGenSection(
894             out,
895             packageFQName,
896             hidl_gen,
897             coordinator,
898             halFilegroupName,
899             genHeaderName,
900             "c++-headers",
901             packageInterfaces,
902             importedPackagesHierarchy,
903             [&pathPrefix](Formatter &out, const FQName &fqName) {
904                 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
905                 if (fqName.name() != "types") {
906                     out << "\"" << pathPrefix << fqName.getInterfaceHwName() << ".h\",\n";
907                     out << "\"" << pathPrefix << fqName.getInterfaceStubName() << ".h\",\n";
908                     out << "\"" << pathPrefix << fqName.getInterfaceProxyName() << ".h\",\n";
909                     out << "\"" << pathPrefix << fqName.getInterfacePassthroughName() << ".h\",\n";
910                 } else {
911                     out << "\"" << pathPrefix << "hwtypes.h\",\n";
912                 }
913             });
914 
915     if (isHidlTransportPackage(packageFQName)) {
916         out << "// " << packageFQName.string() << " is exported from libhidltransport\n";
917     } else {
918         generateAndroidBpLibSection(
919             out,
920             false /* generateVendor */,
921             packageFQName,
922             libraryName,
923             genSourceName,
924             genHeaderName,
925             importedPackagesHierarchy);
926 
927         // TODO(b/35813011): make all libraries vendor_available
928         // Explicitly create '_vendor' copies of libraries so that
929         // vendor code can link against the extensions. When this is
930         // used, framework code should link against vendor.awesome.foo@1.0
931         // and code on the vendor image should link against
932         // vendor.awesome.foo@1.0_vendor. For libraries with the below extensions,
933         // they will be available even on the generic system image.
934         // Because of this, they should always be referenced without the
935         // '_vendor' name suffix.
936         if (!isSystemPackage(packageFQName)) {
937 
938             // Note, not using cc_defaults here since it's already not used and
939             // because generating this libraries will be removed when the VNDK
940             // is enabled (done by the build system itself).
941             out.endl();
942             generateAndroidBpLibSection(
943                 out,
944                 true /* generateVendor */,
945                 packageFQName,
946                 libraryName,
947                 genSourceName,
948                 genHeaderName,
949                 importedPackagesHierarchy);
950         }
951     }
952 
953     return OK;
954 }
955 
generateAndroidBpImplForPackage(const FQName & packageFQName,const char *,Coordinator * coordinator,const std::string & outputDir)956 static status_t generateAndroidBpImplForPackage(
957         const FQName &packageFQName,
958         const char *,
959         Coordinator *coordinator,
960         const std::string &outputDir) {
961 
962     const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
963 
964     std::vector<FQName> packageInterfaces;
965 
966     status_t err =
967         coordinator->appendPackageInterfacesToVector(packageFQName,
968                                                      &packageInterfaces);
969 
970     if (err != OK) {
971         return err;
972     }
973 
974     std::set<FQName> importedPackages;
975 
976     for (const auto &fqName : packageInterfaces) {
977         AST *ast = coordinator->parse(fqName);
978 
979         if (ast == NULL) {
980             fprintf(stderr,
981                     "ERROR: Could not parse %s. Aborting.\n",
982                     fqName.string().c_str());
983 
984             return UNKNOWN_ERROR;
985         }
986 
987         ast->getImportedPackages(&importedPackages);
988     }
989 
990     std::string path = outputDir + "Android.bp";
991 
992     CHECK(Coordinator::MakeParentHierarchy(path));
993     FILE *file = fopen(path.c_str(), "w");
994 
995     if (file == NULL) {
996         return -errno;
997     }
998 
999     Formatter out(file);
1000 
1001     out << "cc_library_shared {\n";
1002     out.indent([&] {
1003         out << "name: \"" << libraryName << "\",\n"
1004             << "relative_install_path: \"hw\",\n"
1005             << "proprietary: true,\n"
1006             << "srcs: [\n";
1007         out.indent([&] {
1008             for (const auto &fqName : packageInterfaces) {
1009                 if (fqName.name() == "types") {
1010                     continue;
1011                 }
1012                 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
1013             }
1014         });
1015         out << "],\n"
1016             << "shared_libs: [\n";
1017         out.indent([&] {
1018             out << "\"libhidlbase\",\n"
1019                 << "\"libhidltransport\",\n"
1020                 << "\"libutils\",\n"
1021                 << "\"" << makeLibraryName(packageFQName) << "\",\n";
1022 
1023             for (const auto &importedPackage : importedPackages) {
1024                 if (isHidlTransportPackage(importedPackage)) {
1025                     continue;
1026                 }
1027 
1028                 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
1029             }
1030         });
1031         out << "],\n";
1032     });
1033     out << "}\n";
1034 
1035     return OK;
1036 }
1037 
validateForSource(const FQName & fqName,const std::string & language)1038 bool validateForSource(
1039         const FQName &fqName, const std::string &language) {
1040     if (fqName.package().empty()) {
1041         fprintf(stderr, "ERROR: Expecting package name\n");
1042         return false;
1043     }
1044 
1045     if (fqName.version().empty()) {
1046         fprintf(stderr, "ERROR: Expecting package version\n");
1047         return false;
1048     }
1049 
1050     const std::string &name = fqName.name();
1051     if (!name.empty()) {
1052         if (name.find('.') == std::string::npos) {
1053             return true;
1054         }
1055 
1056         if (language != "java" || name.find("types.") != 0) {
1057             // When generating java sources for "types.hal", output can be
1058             // constrained to just one of the top-level types declared
1059             // by using the extended syntax
1060             // android.hardware.Foo@1.0::types.TopLevelTypeName.
1061             // In all other cases (different language, not 'types') the dot
1062             // notation in the name is illegal in this context.
1063             return false;
1064         }
1065 
1066         return true;
1067     }
1068 
1069     return true;
1070 }
1071 
generateExportHeaderForPackage(bool forJava)1072 OutputHandler::GenerationFunction generateExportHeaderForPackage(bool forJava) {
1073     return [forJava](const FQName &packageFQName,
1074                      const char * /* hidl_gen */,
1075                      Coordinator *coordinator,
1076                      const std::string &outputPath) -> status_t {
1077         CHECK(packageFQName.isValid()
1078                 && !packageFQName.package().empty()
1079                 && !packageFQName.version().empty()
1080                 && packageFQName.name().empty());
1081 
1082         std::vector<FQName> packageInterfaces;
1083 
1084         status_t err = coordinator->appendPackageInterfacesToVector(
1085                 packageFQName, &packageInterfaces);
1086 
1087         if (err != OK) {
1088             return err;
1089         }
1090 
1091         std::vector<const Type *> exportedTypes;
1092 
1093         for (const auto &fqName : packageInterfaces) {
1094             AST *ast = coordinator->parse(fqName);
1095 
1096             if (ast == NULL) {
1097                 fprintf(stderr,
1098                         "ERROR: Could not parse %s. Aborting.\n",
1099                         fqName.string().c_str());
1100 
1101                 return UNKNOWN_ERROR;
1102             }
1103 
1104             ast->appendToExportedTypesVector(&exportedTypes);
1105         }
1106 
1107         if (exportedTypes.empty()) {
1108             return OK;
1109         }
1110 
1111         std::string path = outputPath;
1112 
1113         if (forJava) {
1114             path.append(coordinator->convertPackageRootToPath(packageFQName));
1115 
1116             path.append(coordinator->getPackagePath(
1117                         packageFQName, true /* relative */, true /* sanitized */));
1118 
1119             path.append("Constants.java");
1120         }
1121 
1122         CHECK(Coordinator::MakeParentHierarchy(path));
1123         FILE *file = fopen(path.c_str(), "w");
1124 
1125         if (file == nullptr) {
1126             return -errno;
1127         }
1128 
1129         Formatter out(file);
1130 
1131         out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
1132             << "// Source: " << packageFQName.string() << "\n"
1133             << "// Root: " << coordinator->getPackageRootOption(packageFQName) << "\n\n";
1134 
1135         std::string guard;
1136         if (forJava) {
1137             out << "package " << packageFQName.javaPackage() << ";\n\n";
1138             out << "public class Constants {\n";
1139             out.indent();
1140         } else {
1141             guard = "HIDL_GENERATED_";
1142             guard += StringHelper::Uppercase(packageFQName.tokenName());
1143             guard += "_";
1144             guard += "EXPORTED_CONSTANTS_H_";
1145 
1146             out << "#ifndef "
1147                 << guard
1148                 << "\n#define "
1149                 << guard
1150                 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
1151         }
1152 
1153         for (const auto &type : exportedTypes) {
1154             type->emitExportedHeader(out, forJava);
1155         }
1156 
1157         if (forJava) {
1158             out.unindent();
1159             out << "}\n";
1160         } else {
1161             out << "#ifdef __cplusplus\n}\n#endif\n\n#endif  // "
1162                 << guard
1163                 << "\n";
1164         }
1165 
1166         return OK;
1167     };
1168 }
1169 
generateHashOutput(const FQName & fqName,const char *,Coordinator * coordinator,const std::string &)1170 static status_t generateHashOutput(const FQName &fqName,
1171         const char* /*hidl_gen*/,
1172         Coordinator *coordinator,
1173         const std::string & /*outputDir*/) {
1174 
1175     status_t err;
1176     std::vector<FQName> packageInterfaces;
1177 
1178     if (fqName.isFullyQualified()) {
1179         packageInterfaces = {fqName};
1180     } else {
1181         err = coordinator->appendPackageInterfacesToVector(
1182                 fqName, &packageInterfaces);
1183         if (err != OK) {
1184             return err;
1185         }
1186     }
1187 
1188     for (const auto &currentFqName : packageInterfaces) {
1189         AST* ast = coordinator->parse(currentFqName, {} /* parsed */,
1190                                       Coordinator::Enforce::NO_HASH /* enforcement */);
1191 
1192         if (ast == NULL) {
1193             fprintf(stderr,
1194                     "ERROR: Could not parse %s. Aborting.\n",
1195                     currentFqName.string().c_str());
1196 
1197             return UNKNOWN_ERROR;
1198         }
1199 
1200         printf("%s %s\n",
1201                 Hash::getHash(ast->getFilename()).hexString().c_str(),
1202                 currentFqName.string().c_str());
1203     }
1204 
1205     return OK;
1206 }
1207 
1208 static std::vector<OutputHandler> formats = {
1209     {"check",
1210      "Parses the interface to see if valid but doesn't write any files.",
1211      OutputHandler::NOT_NEEDED /* mOutputMode */,
1212      validateForSource,
1213      generationFunctionForFileOrPackage("check")
1214     },
1215 
1216     {"c++",
1217      "(internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.",
1218      OutputHandler::NEEDS_DIR /* mOutputMode */,
1219      validateForSource,
1220      generationFunctionForFileOrPackage("c++")
1221     },
1222 
1223     {"c++-headers",
1224      "(internal) Generates C++ headers for interface files for talking to HIDL interfaces.",
1225      OutputHandler::NEEDS_DIR /* mOutputMode */,
1226      validateForSource,
1227      generationFunctionForFileOrPackage("c++-headers")
1228     },
1229 
1230     {"c++-sources",
1231      "(internal) Generates C++ sources for interface files for talking to HIDL interfaces.",
1232      OutputHandler::NEEDS_DIR /* mOutputMode */,
1233      validateForSource,
1234      generationFunctionForFileOrPackage("c++-sources")
1235     },
1236 
1237     {"export-header",
1238      "Generates a header file from @export enumerations to help maintain legacy code.",
1239      OutputHandler::NEEDS_FILE /* mOutputMode */,
1240      validateIsPackage,
1241      generateExportHeaderForPackage(false /* forJava */)
1242     },
1243 
1244     {"c++-impl",
1245      "Generates boilerplate implementation of a hidl interface in C++ (for convenience).",
1246      OutputHandler::NEEDS_DIR /* mOutputMode */,
1247      validateForSource,
1248      generationFunctionForFileOrPackage("c++-impl")
1249     },
1250     {"c++-impl-headers",
1251      "c++-impl but headers only",
1252      OutputHandler::NEEDS_DIR /* mOutputMode */,
1253      validateForSource,
1254      generationFunctionForFileOrPackage("c++-impl-headers")
1255     },
1256     {"c++-impl-sources",
1257      "c++-impl but sources only",
1258      OutputHandler::NEEDS_DIR /* mOutputMode */,
1259      validateForSource,
1260      generationFunctionForFileOrPackage("c++-impl-sources")
1261     },
1262 
1263     {"java",
1264      "(internal) Generates Java library for talking to HIDL interfaces in Java.",
1265      OutputHandler::NEEDS_DIR /* mOutputMode */,
1266      validateForSource,
1267      generationFunctionForFileOrPackage("java")
1268     },
1269 
1270     {"java-constants",
1271      "(internal) Like export-header but for Java (always created by -Lmakefile if @export exists).",
1272      OutputHandler::NEEDS_DIR /* mOutputMode */,
1273      validateIsPackage,
1274      generateExportHeaderForPackage(true /* forJava */)
1275     },
1276 
1277     {"vts",
1278      "(internal) Generates vts proto files for use in vtsd.",
1279      OutputHandler::NEEDS_DIR /* mOutputMode */,
1280      validateForSource,
1281      generationFunctionForFileOrPackage("vts")
1282     },
1283 
1284     {"makefile",
1285      "(internal) Generates makefiles for -Ljava and -Ljava-constants.",
1286      OutputHandler::NEEDS_SRC /* mOutputMode */,
1287      validateIsPackage,
1288      generateMakefileForPackage,
1289     },
1290 
1291     {"androidbp",
1292      "(internal) Generates Soong bp files for -Lc++-headers and -Lc++-sources.",
1293      OutputHandler::NEEDS_SRC /* mOutputMode */,
1294      validateIsPackage,
1295      generateAndroidBpForPackage,
1296     },
1297 
1298     {"androidbp-impl",
1299      "Generates boilerplate bp files for implementation created with -Lc++-impl.",
1300      OutputHandler::NEEDS_DIR /* mOutputMode */,
1301      validateIsPackage,
1302      generateAndroidBpImplForPackage,
1303     },
1304 
1305     {"hash",
1306      "Prints hashes of interface in `current.txt` format to standard out.",
1307      OutputHandler::NOT_NEEDED /* mOutputMode */,
1308      validateForSource,
1309      generateHashOutput,
1310     },
1311 };
1312 
usage(const char * me)1313 static void usage(const char *me) {
1314     fprintf(stderr,
1315             "usage: %s [-p <root path>] -o <output path> -L <language> (-r <interface root>)+ [-t] "
1316             "fqname+\n",
1317             me);
1318 
1319     fprintf(stderr, "         -h: Prints this menu.\n");
1320     fprintf(stderr, "         -L <language>: The following options are available:\n");
1321     for (auto &e : formats) {
1322         fprintf(stderr, "            %-16s: %s\n", e.name().c_str(), e.description().c_str());
1323     }
1324     fprintf(stderr, "         -o <output path>: Location to output files.\n");
1325     fprintf(stderr, "         -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.\n");
1326     fprintf(stderr, "         -r <package:path root>: E.g., android.hardware:hardware/interfaces.\n");
1327     fprintf(stderr, "         -t: generate build scripts (Android.bp) for tests.\n");
1328 }
1329 
1330 // hidl is intentionally leaky. Turn off LeakSanitizer by default.
__asan_default_options()1331 extern "C" const char *__asan_default_options() {
1332     return "detect_leaks=0";
1333 }
1334 
main(int argc,char ** argv)1335 int main(int argc, char **argv) {
1336     std::string outputPath;
1337     std::string rootPath;
1338     std::vector<std::string> packageRootPaths;
1339     std::vector<std::string> packageRoots;
1340 
1341     const char *me = argv[0];
1342     OutputHandler *outputFormat = nullptr;
1343 
1344     if (argc == 1) {
1345         usage(me);
1346         exit(1);
1347     }
1348 
1349     int res;
1350     while ((res = getopt(argc, argv, "hp:o:r:L:t")) >= 0) {
1351         switch (res) {
1352             case 'p':
1353             {
1354                 rootPath = optarg;
1355                 break;
1356             }
1357 
1358             case 'o':
1359             {
1360                 outputPath = optarg;
1361                 break;
1362             }
1363 
1364             case 'r':
1365             {
1366                 std::string val(optarg);
1367                 auto index = val.find_first_of(':');
1368                 if (index == std::string::npos) {
1369                     fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
1370                     exit(1);
1371                 }
1372 
1373                 auto package = val.substr(0, index);
1374                 auto path = val.substr(index + 1);
1375                 packageRootPaths.push_back(path);
1376                 packageRoots.push_back(package);
1377                 break;
1378             }
1379 
1380             case 'L':
1381             {
1382                 if (outputFormat != nullptr) {
1383                     fprintf(stderr,
1384                             "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1385                             outputFormat->name().c_str());
1386                     exit(1);
1387                 }
1388                 for (auto &e : formats) {
1389                     if (e.name() == optarg) {
1390                         outputFormat = &e;
1391                         break;
1392                     }
1393                 }
1394                 if (outputFormat == nullptr) {
1395                     fprintf(stderr,
1396                             "ERROR: unrecognized -L option: \"%s\".\n",
1397                             optarg);
1398                     exit(1);
1399                 }
1400                 break;
1401             }
1402 
1403             case 't': {
1404                 generateForTest = true;
1405                 break;
1406             }
1407 
1408             case '?':
1409             case 'h':
1410             default:
1411             {
1412                 usage(me);
1413                 exit(1);
1414                 break;
1415             }
1416         }
1417     }
1418 
1419     if (outputFormat == nullptr) {
1420         fprintf(stderr,
1421             "ERROR: no -L option provided.\n");
1422         exit(1);
1423     }
1424 
1425     if (generateForTest && outputFormat->name() != "androidbp") {
1426         fprintf(stderr, "ERROR: -t option is for -Landroidbp only.\n");
1427         exit(1);
1428     }
1429 
1430     argc -= optind;
1431     argv += optind;
1432 
1433     if (argc == 0) {
1434         fprintf(stderr, "ERROR: no fqname specified.\n");
1435         usage(me);
1436         exit(1);
1437     }
1438 
1439     if (rootPath.empty()) {
1440         const char *ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
1441 
1442         if (ANDROID_BUILD_TOP != nullptr) {
1443             rootPath = ANDROID_BUILD_TOP;
1444         }
1445 
1446         // else default to pwd
1447     }
1448 
1449     if (!rootPath.empty() && !StringHelper::EndsWith(rootPath, "/")) {
1450         rootPath += "/";
1451     }
1452 
1453     // Valid options are now in argv[0] .. argv[argc - 1].
1454 
1455     switch (outputFormat->mOutputMode) {
1456         case OutputHandler::NEEDS_DIR:
1457         case OutputHandler::NEEDS_FILE:
1458         {
1459             if (outputPath.empty()) {
1460                 usage(me);
1461                 exit(1);
1462             }
1463 
1464             if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1465                 const size_t len = outputPath.size();
1466                 if (outputPath[len - 1] != '/') {
1467                     outputPath += "/";
1468                 }
1469             }
1470             break;
1471         }
1472         case OutputHandler::NEEDS_SRC:
1473         {
1474             if (outputPath.empty()) {
1475                 outputPath = rootPath;
1476             }
1477 
1478             break;
1479         }
1480 
1481         default:
1482             outputPath.clear();  // Unused.
1483             break;
1484     }
1485 
1486     Coordinator coordinator(packageRootPaths, packageRoots, rootPath);
1487     coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
1488     coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
1489     coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
1490     coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
1491 
1492     for (int i = 0; i < argc; ++i) {
1493         FQName fqName(argv[i]);
1494 
1495         if (!fqName.isValid()) {
1496             fprintf(stderr,
1497                     "ERROR: Invalid fully-qualified name.\n");
1498             exit(1);
1499         }
1500 
1501         if (!outputFormat->validate(fqName, outputFormat->name())) {
1502             fprintf(stderr,
1503                     "ERROR: output handler failed.\n");
1504             exit(1);
1505         }
1506 
1507         status_t err =
1508             outputFormat->generate(fqName, me, &coordinator, outputPath);
1509 
1510         if (err != OK) {
1511             exit(1);
1512         }
1513     }
1514 
1515     return 0;
1516 }
1517