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