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 ¤tFqName : 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