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