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 <android-base/logging.h>
22 #include <hidl-hash/Hash.h>
23 #include <hidl-util/FQName.h>
24 #include <hidl-util/Formatter.h>
25 #include <hidl-util/StringHelper.h>
26 #include <stdio.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <iostream>
30 #include <set>
31 #include <string>
32 #include <vector>
33
34 using namespace android;
35
36 enum class OutputMode {
37 NEEDS_DIR, // -o output option expects a directory
38 NEEDS_FILE, // -o output option expects a file
39 NEEDS_SRC, // for changes inside the source tree itself
40 NOT_NEEDED // does not create files
41 };
42
43 enum class GenerationGranularity {
44 PER_PACKAGE, // Files generated for each package
45 PER_FILE, // Files generated for each hal file
46 PER_TYPE, // Files generated for each hal file + each type in HAL files
47 };
48
49 // Represents a file that is generated by an -L option for an FQName
50 struct FileGenerator {
51 using ShouldGenerateFunction = std::function<bool(const FQName& fqName)>;
52 using FileNameForFQName = std::function<std::string(const FQName& fqName)>;
53 using GenerationFunction = std::function<status_t(Formatter& out, const FQName& fqName,
54 const Coordinator* coordinator)>;
55
56 ShouldGenerateFunction mShouldGenerateForFqName; // If generate function applies to this target
57 FileNameForFQName mFileNameForFqName; // Target -> filename
58 GenerationFunction mGenerationFunction; // Function to generate output for file
59
getFileNameFileGenerator60 std::string getFileName(const FQName& fqName) const {
61 return mFileNameForFqName ? mFileNameForFqName(fqName) : "";
62 }
63
getOutputFileFileGenerator64 status_t getOutputFile(const FQName& fqName, const Coordinator* coordinator,
65 Coordinator::Location location, std::string* file) const {
66 if (!mShouldGenerateForFqName(fqName)) {
67 return OK;
68 }
69
70 return coordinator->getFilepath(fqName, location, getFileName(fqName), file);
71 }
72
appendOutputFilesFileGenerator73 status_t appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
74 Coordinator::Location location,
75 std::vector<std::string>* outputFiles) const {
76 if (location == Coordinator::Location::STANDARD_OUT) {
77 return OK;
78 }
79
80 if (mShouldGenerateForFqName(fqName)) {
81 std::string fileName;
82 status_t err = getOutputFile(fqName, coordinator, location, &fileName);
83 if (err != OK) return err;
84
85 if (!fileName.empty()) {
86 outputFiles->push_back(fileName);
87 }
88 }
89 return OK;
90 }
91
generateFileGenerator92 status_t generate(const FQName& fqName, const Coordinator* coordinator,
93 Coordinator::Location location) const {
94 CHECK(mShouldGenerateForFqName != nullptr);
95 CHECK(mGenerationFunction != nullptr);
96
97 if (!mShouldGenerateForFqName(fqName)) {
98 return OK;
99 }
100
101 Formatter out = coordinator->getFormatter(fqName, location, getFileName(fqName));
102 if (!out.isValid()) {
103 return UNKNOWN_ERROR;
104 }
105
106 return mGenerationFunction(out, fqName, coordinator);
107 }
108
109 // Helper methods for filling out this struct
generateForTypesFileGenerator110 static bool generateForTypes(const FQName& fqName) {
111 const auto names = fqName.names();
112 return names.size() > 0 && names[0] == "types";
113 }
generateForInterfacesFileGenerator114 static bool generateForInterfaces(const FQName& fqName) { return !generateForTypes(fqName); }
alwaysGenerateFileGenerator115 static bool alwaysGenerate(const FQName&) { return true; }
116 };
117
118 // Represents a -L option, takes a fqName and generates files
119 struct OutputHandler {
120 using ValidationFunction = std::function<bool(
121 const FQName& fqName, const Coordinator* coordinator, const std::string& language)>;
122
123 std::string mKey; // -L in Android.bp
124 std::string mDescription; // for display in help menu
125 OutputMode mOutputMode; // how this option interacts with -o
126 Coordinator::Location mLocation; // how to compute location relative to the output directory
127 GenerationGranularity mGenerationGranularity; // what to run generate function on
128 ValidationFunction mValidate; // if a given fqName is allowed for this option
129 std::vector<FileGenerator> mGenerateFunctions; // run for each target at this granularity
130
nameOutputHandler131 const std::string& name() const { return mKey; }
descriptionOutputHandler132 const std::string& description() const { return mDescription; }
133
134 status_t generate(const FQName& fqName, const Coordinator* coordinator) const;
validateOutputHandler135 status_t validate(const FQName& fqName, const Coordinator* coordinator,
136 const std::string& language) const {
137 return mValidate(fqName, coordinator, language);
138 }
139
140 status_t writeDepFile(const FQName& fqName, const Coordinator* coordinator) const;
141
142 private:
143 status_t appendTargets(const FQName& fqName, const Coordinator* coordinator,
144 std::vector<FQName>* targets) const;
145 status_t appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
146 std::vector<std::string>* outputFiles) const;
147 };
148
149 // Helper method for GenerationGranularity::PER_TYPE
150 // IFoo -> IFoo, types.hal (containing Bar, Baz) -> types.Bar, types.Baz
appendPerTypeTargets(const FQName & fqName,const Coordinator * coordinator,std::vector<FQName> * exportedPackageInterfaces)151 static status_t appendPerTypeTargets(const FQName& fqName, const Coordinator* coordinator,
152 std::vector<FQName>* exportedPackageInterfaces) {
153 CHECK(fqName.isFullyQualified());
154 if (fqName.name() != "types") {
155 exportedPackageInterfaces->push_back(fqName);
156 return OK;
157 }
158
159 AST* typesAST = coordinator->parse(fqName);
160 if (typesAST == nullptr) {
161 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
162 return UNKNOWN_ERROR;
163 }
164
165 std::vector<NamedType*> rootTypes = typesAST->getRootScope()->getSubTypes();
166 for (const NamedType* rootType : rootTypes) {
167 if (rootType->isTypeDef()) continue;
168
169 FQName rootTypeName(fqName.package(), fqName.version(), "types." + rootType->localName());
170 exportedPackageInterfaces->push_back(rootTypeName);
171 }
172 return OK;
173 }
174
appendTargets(const FQName & fqName,const Coordinator * coordinator,std::vector<FQName> * targets) const175 status_t OutputHandler::appendTargets(const FQName& fqName, const Coordinator* coordinator,
176 std::vector<FQName>* targets) const {
177 switch (mGenerationGranularity) {
178 case GenerationGranularity::PER_PACKAGE: {
179 targets->push_back(fqName.getPackageAndVersion());
180 } break;
181 case GenerationGranularity::PER_FILE: {
182 if (fqName.isFullyQualified()) {
183 targets->push_back(fqName);
184 break;
185 }
186 status_t err = coordinator->appendPackageInterfacesToVector(fqName, targets);
187 if (err != OK) return err;
188 } break;
189 case GenerationGranularity::PER_TYPE: {
190 if (fqName.isFullyQualified()) {
191 status_t err = appendPerTypeTargets(fqName, coordinator, targets);
192 if (err != OK) return err;
193 }
194
195 std::vector<FQName> packageInterfaces;
196 status_t err = coordinator->appendPackageInterfacesToVector(fqName, &packageInterfaces);
197 if (err != OK) return err;
198 for (const FQName& packageInterface : packageInterfaces) {
199 err = appendPerTypeTargets(packageInterface, coordinator, targets);
200 if (err != OK) return err;
201 }
202 } break;
203 default:
204 CHECK(!"Should be here");
205 }
206
207 return OK;
208 }
209
generate(const FQName & fqName,const Coordinator * coordinator) const210 status_t OutputHandler::generate(const FQName& fqName, const Coordinator* coordinator) const {
211 std::vector<FQName> targets;
212 status_t err = appendTargets(fqName, coordinator, &targets);
213 if (err != OK) return err;
214
215 for (const FQName& fqName : targets) {
216 for (const FileGenerator& file : mGenerateFunctions) {
217 status_t err = file.generate(fqName, coordinator, mLocation);
218 if (err != OK) return err;
219 }
220 }
221
222 return OK;
223 }
224
appendOutputFiles(const FQName & fqName,const Coordinator * coordinator,std::vector<std::string> * outputFiles) const225 status_t OutputHandler::appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
226 std::vector<std::string>* outputFiles) const {
227 std::vector<FQName> targets;
228 status_t err = appendTargets(fqName, coordinator, &targets);
229 if (err != OK) return err;
230
231 for (const FQName& fqName : targets) {
232 for (const FileGenerator& file : mGenerateFunctions) {
233 err = file.appendOutputFiles(fqName, coordinator, mLocation, outputFiles);
234 if (err != OK) return err;
235 }
236 }
237
238 return OK;
239 }
240
writeDepFile(const FQName & fqName,const Coordinator * coordinator) const241 status_t OutputHandler::writeDepFile(const FQName& fqName, const Coordinator* coordinator) const {
242 std::vector<std::string> outputFiles;
243 status_t err = appendOutputFiles(fqName, coordinator, &outputFiles);
244 if (err != OK) return err;
245
246 // No need for dep files
247 if (outputFiles.empty()) {
248 return OK;
249 }
250
251 // Depfiles in Android for genrules should be for the 'main file'. Because hidl-gen doesn't have
252 // a main file for most targets, we are just outputting a depfile for one single file only.
253 const std::string forFile = outputFiles[0];
254
255 return coordinator->writeDepFile(forFile);
256 }
257
258 // Use an AST function as a OutputHandler GenerationFunction
astGenerationFunction(void (AST::* generate)(Formatter &)const=nullptr)259 static FileGenerator::GenerationFunction astGenerationFunction(void (AST::*generate)(Formatter&)
260 const = nullptr) {
261 return [generate](Formatter& out, const FQName& fqName,
262 const Coordinator* coordinator) -> status_t {
263 AST* ast = coordinator->parse(fqName);
264 if (ast == nullptr) {
265 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
266 return UNKNOWN_ERROR;
267 }
268
269 if (generate == nullptr) return OK; // just parsing AST
270 (ast->*generate)(out);
271
272 return OK;
273 };
274 }
275
276 // Common pattern: single file for package or standard out
singleFileGenerator(const std::string & fileName,const FileGenerator::GenerationFunction & generationFunction)277 static FileGenerator singleFileGenerator(
278 const std::string& fileName, const FileGenerator::GenerationFunction& generationFunction) {
279 return {
280 FileGenerator::alwaysGenerate, [fileName](const FQName&) { return fileName; },
281 generationFunction,
282 };
283 }
284
generateJavaForPackage(Formatter & out,const FQName & fqName,const Coordinator * coordinator)285 static status_t generateJavaForPackage(Formatter& out, const FQName& fqName,
286 const Coordinator* coordinator) {
287 AST* ast;
288 std::string limitToType;
289
290 // Required for legacy -Lmakefile files
291 if (fqName.name().find("types.") == 0) {
292 limitToType = fqName.name().substr(strlen("types."));
293
294 FQName typesName = fqName.getTypesForPackage();
295 ast = coordinator->parse(typesName);
296 } else {
297 ast = coordinator->parse(fqName);
298 }
299 if (ast == nullptr) {
300 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
301 return UNKNOWN_ERROR;
302 }
303 ast->generateJava(out, limitToType);
304 return OK;
305 };
306
dumpDefinedButUnreferencedTypeNames(const FQName & packageFQName,const Coordinator * coordinator)307 static status_t dumpDefinedButUnreferencedTypeNames(const FQName& packageFQName,
308 const Coordinator* coordinator) {
309 std::vector<FQName> packageInterfaces;
310 status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
311 if (err != OK) return err;
312
313 std::set<FQName> unreferencedDefinitions;
314 std::set<FQName> unreferencedImports;
315 err = coordinator->addUnreferencedTypes(packageInterfaces, &unreferencedDefinitions,
316 &unreferencedImports);
317 if (err != OK) return err;
318
319 for (const auto& fqName : unreferencedDefinitions) {
320 std::cerr
321 << "VERBOSE: DEFINED-BUT-NOT-REFERENCED "
322 << fqName.string()
323 << std::endl;
324 }
325
326 for (const auto& fqName : unreferencedImports) {
327 std::cerr
328 << "VERBOSE: IMPORTED-BUT-NOT-REFERENCED "
329 << fqName.string()
330 << std::endl;
331 }
332
333 return OK;
334 }
335
makeLibraryName(const FQName & packageFQName)336 static std::string makeLibraryName(const FQName &packageFQName) {
337 return packageFQName.string();
338 }
339
isPackageJavaCompatible(const FQName & packageFQName,const Coordinator * coordinator,bool * compatible)340 static status_t isPackageJavaCompatible(const FQName& packageFQName, const Coordinator* coordinator,
341 bool* compatible) {
342 std::vector<FQName> todo;
343 status_t err =
344 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
345
346 if (err != OK) {
347 return err;
348 }
349
350 std::set<FQName> seen;
351 for (const auto &iface : todo) {
352 seen.insert(iface);
353 }
354
355 // Form the transitive closure of all imported interfaces (and types.hal-s)
356 // If any one of them is not java compatible, this package isn't either.
357 while (!todo.empty()) {
358 const FQName fqName = todo.back();
359 todo.pop_back();
360
361 AST *ast = coordinator->parse(fqName);
362
363 if (ast == nullptr) {
364 return UNKNOWN_ERROR;
365 }
366
367 if (!ast->isJavaCompatible()) {
368 *compatible = false;
369 return OK;
370 }
371
372 std::set<FQName> importedPackages;
373 ast->getImportedPackages(&importedPackages);
374
375 for (const auto &package : importedPackages) {
376 std::vector<FQName> packageInterfaces;
377 status_t err = coordinator->appendPackageInterfacesToVector(
378 package, &packageInterfaces);
379
380 if (err != OK) {
381 return err;
382 }
383
384 for (const auto &iface : packageInterfaces) {
385 if (seen.find(iface) != seen.end()) {
386 continue;
387 }
388
389 todo.push_back(iface);
390 seen.insert(iface);
391 }
392 }
393 }
394
395 *compatible = true;
396 return OK;
397 }
398
packageNeedsJavaCode(const std::vector<FQName> & packageInterfaces,AST * typesAST)399 static bool packageNeedsJavaCode(
400 const std::vector<FQName> &packageInterfaces, AST *typesAST) {
401 if (packageInterfaces.size() == 0) {
402 return false;
403 }
404
405 // If there is more than just a types.hal file to this package we'll
406 // definitely need to generate Java code.
407 if (packageInterfaces.size() > 1
408 || packageInterfaces[0].name() != "types") {
409 return true;
410 }
411
412 CHECK(typesAST != nullptr);
413
414 // We'll have to generate Java code if types.hal contains any non-typedef
415 // type declarations.
416
417 Scope* rootScope = typesAST->getRootScope();
418 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
419
420 for (const auto &subType : subTypes) {
421 if (!subType->isTypeDef()) {
422 return true;
423 }
424 }
425
426 return false;
427 }
428
validateIsPackage(const FQName & fqName,const Coordinator *,const std::string &)429 bool validateIsPackage(const FQName& fqName, const Coordinator*,
430 const std::string& /* language */) {
431 if (fqName.package().empty()) {
432 fprintf(stderr, "ERROR: Expecting package name\n");
433 return false;
434 }
435
436 if (fqName.version().empty()) {
437 fprintf(stderr, "ERROR: Expecting package version\n");
438 return false;
439 }
440
441 if (!fqName.name().empty()) {
442 fprintf(stderr,
443 "ERROR: Expecting only package name and version.\n");
444 return false;
445 }
446
447 return true;
448 }
449
isHidlTransportPackage(const FQName & fqName)450 bool isHidlTransportPackage(const FQName& fqName) {
451 return fqName.package() == gIBaseFqName.package() ||
452 fqName.package() == gIManagerFqName.package();
453 }
454
isSystemProcessSupportedPackage(const FQName & fqName)455 bool isSystemProcessSupportedPackage(const FQName& fqName) {
456 // Technically, so is hidl IBase + IServiceManager, but
457 // these are part of libhidltransport.
458 return fqName.string() == "android.hardware.graphics.common@1.0" ||
459 fqName.string() == "android.hardware.graphics.common@1.1" ||
460 fqName.string() == "android.hardware.graphics.mapper@2.0" ||
461 fqName.string() == "android.hardware.graphics.mapper@2.1" ||
462 fqName.string() == "android.hardware.renderscript@1.0" ||
463 fqName.string() == "android.hidl.memory.token@1.0" ||
464 fqName.string() == "android.hidl.memory@1.0";
465 }
466
isSystemPackage(const FQName & package)467 bool isSystemPackage(const FQName &package) {
468 return package.inPackage("android.hidl") ||
469 package.inPackage("android.system") ||
470 package.inPackage("android.frameworks") ||
471 package.inPackage("android.hardware");
472 }
473
474 // TODO(b/69862859): remove special case
isTestPackage(const FQName & fqName,const Coordinator * coordinator,bool * isTestPackage)475 status_t isTestPackage(const FQName& fqName, const Coordinator* coordinator, bool* isTestPackage) {
476 const auto fileExists = [](const std::string& file) {
477 struct stat buf;
478 return stat(file.c_str(), &buf) == 0;
479 };
480
481 std::string path;
482 status_t err = coordinator->getFilepath(fqName, Coordinator::Location::PACKAGE_ROOT,
483 ".hidl_for_test", &path);
484 if (err != OK) return err;
485
486 const bool exists = fileExists(path);
487
488 if (exists) {
489 coordinator->onFileAccess(path, "r");
490 }
491
492 *isTestPackage = exists;
493 return OK;
494 }
495
generateAdapterMainSource(Formatter & out,const FQName & packageFQName,const Coordinator * coordinator)496 static status_t generateAdapterMainSource(Formatter& out, const FQName& packageFQName,
497 const Coordinator* coordinator) {
498 std::vector<FQName> packageInterfaces;
499 status_t err =
500 coordinator->appendPackageInterfacesToVector(packageFQName,
501 &packageInterfaces);
502 if (err != OK) {
503 return err;
504 }
505
506 out << "#include <hidladapter/HidlBinderAdapter.h>\n";
507
508 for (auto &interface : packageInterfaces) {
509 if (interface.name() == "types") {
510 continue;
511 }
512 AST::generateCppPackageInclude(out, interface, interface.getInterfaceAdapterName());
513 }
514
515 out << "int main(int argc, char** argv) ";
516 out.block([&] {
517 out << "return ::android::hardware::adapterMain<\n";
518 out.indent();
519 for (auto &interface : packageInterfaces) {
520 if (interface.name() == "types") {
521 continue;
522 }
523 out << interface.getInterfaceAdapterFqName().cppName();
524
525 if (&interface != &packageInterfaces.back()) {
526 out << ",\n";
527 }
528 }
529 out << ">(\"" << packageFQName.string() << "\", argc, argv);\n";
530 out.unindent();
531 }).endl();
532 return OK;
533 }
534
generateAndroidBpForPackage(Formatter & out,const FQName & packageFQName,const Coordinator * coordinator)535 static status_t generateAndroidBpForPackage(Formatter& out, const FQName& packageFQName,
536 const Coordinator* coordinator) {
537 CHECK(packageFQName.isValid() && !packageFQName.isFullyQualified() &&
538 packageFQName.name().empty());
539
540 std::vector<FQName> packageInterfaces;
541
542 status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
543
544 if (err != OK) {
545 return err;
546 }
547
548 std::set<FQName> importedPackagesHierarchy;
549 std::vector<const Type *> exportedTypes;
550 AST* typesAST = nullptr;
551
552 for (const auto& fqName : packageInterfaces) {
553 AST* ast = coordinator->parse(fqName);
554
555 if (ast == NULL) {
556 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
557
558 return UNKNOWN_ERROR;
559 }
560
561 if (fqName.name() == "types") {
562 typesAST = ast;
563 }
564
565 ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
566 ast->appendToExportedTypesVector(&exportedTypes);
567 }
568
569 bool needsJavaCode = packageNeedsJavaCode(packageInterfaces, typesAST);
570
571 bool genJavaConstants = needsJavaCode && !exportedTypes.empty();
572
573 bool isJavaCompatible;
574 err = isPackageJavaCompatible(packageFQName, coordinator, &isJavaCompatible);
575 if (err != OK) return err;
576 bool genJavaLibrary = needsJavaCode && isJavaCompatible;
577
578 bool generateForTest;
579 err = isTestPackage(packageFQName, coordinator, &generateForTest);
580 if (err != OK) return err;
581
582 bool isVndk = !generateForTest && isSystemPackage(packageFQName);
583 bool isVndkSp = isVndk && isSystemProcessSupportedPackage(packageFQName);
584
585 std::string packageRoot;
586 err = coordinator->getPackageRoot(packageFQName, &packageRoot);
587 if (err != OK) return err;
588
589 out << "// This file is autogenerated by hidl-gen -Landroidbp.\n\n";
590
591 out << "hidl_interface ";
592 out.block([&] {
593 out << "name: \"" << makeLibraryName(packageFQName) << "\",\n";
594 if (!coordinator->getOwner().empty()) {
595 out << "owner: \"" << coordinator->getOwner() << "\",\n";
596 }
597 out << "root: \"" << packageRoot << "\",\n";
598 if (isHidlTransportPackage(packageFQName)) {
599 out << "core_interface: true,\n";
600 }
601 if (isVndk) {
602 out << "vndk: ";
603 out.block([&]() {
604 out << "enabled: true,\n";
605 if (isVndkSp) {
606 out << "support_system_process: true,\n";
607 }
608 }) << ",\n";
609 }
610 (out << "srcs: [\n").indent([&] {
611 for (const auto& fqName : packageInterfaces) {
612 out << "\"" << fqName.name() << ".hal\",\n";
613 }
614 }) << "],\n";
615 if (!importedPackagesHierarchy.empty()) {
616 (out << "interfaces: [\n").indent([&] {
617 for (const auto& fqName : importedPackagesHierarchy) {
618 out << "\"" << fqName.string() << "\",\n";
619 }
620 }) << "],\n";
621 }
622 if (typesAST != nullptr) {
623 (out << "types: [\n").indent([&] {
624 std::vector<NamedType *> subTypes = typesAST->getRootScope()->getSubTypes();
625 std::sort(
626 subTypes.begin(),
627 subTypes.end(),
628 [](const NamedType *a, const NamedType *b) -> bool {
629 return a->fqName() < b->fqName();
630 });
631
632 for (const auto &type : subTypes) {
633 if (type->isTypeDef()) {
634 continue;
635 }
636
637 out << "\"" << type->localName() << "\",\n";
638 }
639 }) << "],\n";
640 }
641 // Explicity call this out for developers.
642 out << "gen_java: " << (genJavaLibrary ? "true" : "false") << ",\n";
643 if (genJavaConstants) {
644 out << "gen_java_constants: true,\n";
645 }
646 }).endl().endl();
647
648 return OK;
649 }
650
generateAndroidBpImplForPackage(Formatter & out,const FQName & packageFQName,const Coordinator * coordinator)651 static status_t generateAndroidBpImplForPackage(Formatter& out, const FQName& packageFQName,
652 const Coordinator* coordinator) {
653 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
654
655 std::vector<FQName> packageInterfaces;
656
657 status_t err =
658 coordinator->appendPackageInterfacesToVector(packageFQName,
659 &packageInterfaces);
660
661 if (err != OK) {
662 return err;
663 }
664
665 std::set<FQName> importedPackages;
666
667 for (const auto &fqName : packageInterfaces) {
668 AST *ast = coordinator->parse(fqName);
669
670 if (ast == NULL) {
671 fprintf(stderr,
672 "ERROR: Could not parse %s. Aborting.\n",
673 fqName.string().c_str());
674
675 return UNKNOWN_ERROR;
676 }
677
678 ast->getImportedPackages(&importedPackages);
679 }
680
681 out << "cc_library_shared {\n";
682 out.indent([&] {
683 out << "// FIXME: this should only be -impl for a passthrough hal.\n"
684 << "// In most cases, to convert this to a binderized implementation, you should:\n"
685 << "// - change '-impl' to '-service' here and make it a cc_binary instead of a\n"
686 << "// cc_library_shared.\n"
687 << "// - add a *.rc file for this module.\n"
688 << "// - delete HIDL_FETCH_I* functions.\n"
689 << "// - call configureRpcThreadpool and registerAsService on the instance.\n"
690 << "// You may also want to append '-impl/-service' with a specific identifier like\n"
691 << "// '-vendor' or '-<hardware identifier>' etc to distinguish it.\n";
692 out << "name: \"" << libraryName << "\",\n";
693 if (!coordinator->getOwner().empty()) {
694 out << "owner: \"" << coordinator->getOwner() << "\",\n";
695 }
696 out << "relative_install_path: \"hw\",\n";
697 if (coordinator->getOwner().empty()) {
698 out << "// FIXME: this should be 'vendor: true' for modules that will eventually be\n"
699 "// on AOSP.\n";
700 }
701 out << "proprietary: true,\n";
702 out << "srcs: [\n";
703 out.indent([&] {
704 for (const auto &fqName : packageInterfaces) {
705 if (fqName.name() == "types") {
706 continue;
707 }
708 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
709 }
710 });
711 out << "],\n"
712 << "shared_libs: [\n";
713 out.indent([&] {
714 out << "\"libhidlbase\",\n"
715 << "\"libhidltransport\",\n"
716 << "\"libutils\",\n"
717 << "\"" << makeLibraryName(packageFQName) << "\",\n";
718
719 for (const auto &importedPackage : importedPackages) {
720 if (isHidlTransportPackage(importedPackage)) {
721 continue;
722 }
723
724 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
725 }
726 });
727 out << "],\n";
728 });
729 out << "}\n";
730
731 return OK;
732 }
733
validateForSource(const FQName & fqName,const Coordinator * coordinator,const std::string & language)734 bool validateForSource(const FQName& fqName, const Coordinator* coordinator,
735 const std::string& language) {
736 if (fqName.package().empty()) {
737 fprintf(stderr, "ERROR: Expecting package name\n");
738 return false;
739 }
740
741 if (fqName.version().empty()) {
742 fprintf(stderr, "ERROR: Expecting package version\n");
743 return false;
744 }
745
746 const std::string &name = fqName.name();
747 if (!name.empty()) {
748 if (name.find('.') == std::string::npos) {
749 return true;
750 }
751
752 if (language != "java" || name.find("types.") != 0) {
753 // When generating java sources for "types.hal", output can be
754 // constrained to just one of the top-level types declared
755 // by using the extended syntax
756 // android.hardware.Foo@1.0::types.TopLevelTypeName.
757 // In all other cases (different language, not 'types') the dot
758 // notation in the name is illegal in this context.
759 return false;
760 }
761
762 return true;
763 }
764
765 if (language == "java") {
766 bool isJavaCompatible;
767 status_t err = isPackageJavaCompatible(fqName, coordinator, &isJavaCompatible);
768 if (err != OK) return false;
769
770 if (!isJavaCompatible) {
771 fprintf(stderr,
772 "ERROR: %s is not Java compatible. The Java backend"
773 " does NOT support union types nor native handles. "
774 "In addition, vectors of arrays are limited to at most "
775 "one-dimensional arrays and vectors of {vectors,interfaces} are"
776 " not supported.\n",
777 fqName.string().c_str());
778 return false;
779 }
780 }
781
782 return true;
783 }
784
generateExportHeaderForPackage(bool forJava)785 FileGenerator::GenerationFunction generateExportHeaderForPackage(bool forJava) {
786 return [forJava](Formatter& out, const FQName& packageFQName,
787 const Coordinator* coordinator) -> status_t {
788 CHECK(packageFQName.isValid()
789 && !packageFQName.package().empty()
790 && !packageFQName.version().empty()
791 && packageFQName.name().empty());
792
793 std::vector<FQName> packageInterfaces;
794
795 status_t err = coordinator->appendPackageInterfacesToVector(
796 packageFQName, &packageInterfaces);
797
798 if (err != OK) {
799 return err;
800 }
801
802 std::vector<const Type *> exportedTypes;
803
804 for (const auto &fqName : packageInterfaces) {
805 AST *ast = coordinator->parse(fqName);
806
807 if (ast == NULL) {
808 fprintf(stderr,
809 "ERROR: Could not parse %s. Aborting.\n",
810 fqName.string().c_str());
811
812 return UNKNOWN_ERROR;
813 }
814
815 ast->appendToExportedTypesVector(&exportedTypes);
816 }
817
818 if (exportedTypes.empty()) {
819 return OK;
820 }
821
822 if (!out.isValid()) {
823 return UNKNOWN_ERROR;
824 }
825
826 std::string packagePath;
827 err = coordinator->getPackagePath(packageFQName, false /* relative */,
828 false /* sanitized */, &packagePath);
829 if (err != OK) return err;
830
831 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
832 << "// Source: " << packageFQName.string() << "\n"
833 << "// Location: " << packagePath << "\n\n";
834
835 std::string guard;
836 if (forJava) {
837 out << "package " << packageFQName.javaPackage() << ";\n\n";
838 out << "public class Constants {\n";
839 out.indent();
840 } else {
841 guard = "HIDL_GENERATED_";
842 guard += StringHelper::Uppercase(packageFQName.tokenName());
843 guard += "_";
844 guard += "EXPORTED_CONSTANTS_H_";
845
846 out << "#ifndef "
847 << guard
848 << "\n#define "
849 << guard
850 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
851 }
852
853 for (const auto &type : exportedTypes) {
854 type->emitExportedHeader(out, forJava);
855 }
856
857 if (forJava) {
858 out.unindent();
859 out << "}\n";
860 } else {
861 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
862 << guard
863 << "\n";
864 }
865
866 return OK;
867 };
868 }
869
generateHashOutput(Formatter & out,const FQName & fqName,const Coordinator * coordinator)870 static status_t generateHashOutput(Formatter& out, const FQName& fqName,
871 const Coordinator* coordinator) {
872 CHECK(fqName.isFullyQualified());
873
874 AST* ast = coordinator->parse(fqName, {} /* parsed */,
875 Coordinator::Enforce::NO_HASH /* enforcement */);
876
877 if (ast == NULL) {
878 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
879
880 return UNKNOWN_ERROR;
881 }
882
883 out << Hash::getHash(ast->getFilename()).hexString() << " " << fqName.string() << "\n";
884
885 return OK;
886 }
887
888 template <typename T>
operator +(const std::vector<T> & lhs,const std::vector<T> & rhs)889 std::vector<T> operator+(const std::vector<T>& lhs, const std::vector<T>& rhs) {
890 std::vector<T> ret;
891 ret.reserve(lhs.size() + rhs.size());
892 ret.insert(ret.begin(), lhs.begin(), lhs.end());
893 ret.insert(ret.end(), rhs.begin(), rhs.end());
894 return ret;
895 }
896
897 // clang-format off
898 static const std::vector<FileGenerator> kCppHeaderFormats = {
899 {
900 FileGenerator::alwaysGenerate,
__anonb03561f60f02() 901 [](const FQName& fqName) { return fqName.name() + ".h"; },
902 astGenerationFunction(&AST::generateInterfaceHeader),
903 },
904 {
905 FileGenerator::alwaysGenerate,
__anonb03561f61002() 906 [](const FQName& fqName) {
907 return fqName.isInterfaceName() ? fqName.getInterfaceHwName() + ".h" : "hwtypes.h";
908 },
909 astGenerationFunction(&AST::generateHwBinderHeader),
910 },
911 {
912 FileGenerator::generateForInterfaces,
__anonb03561f61102() 913 [](const FQName& fqName) { return fqName.getInterfaceStubName() + ".h"; },
914 astGenerationFunction(&AST::generateStubHeader),
915 },
916 {
917 FileGenerator::generateForInterfaces,
__anonb03561f61202() 918 [](const FQName& fqName) { return fqName.getInterfaceProxyName() + ".h"; },
919 astGenerationFunction(&AST::generateProxyHeader),
920 },
921 {
922 FileGenerator::generateForInterfaces,
__anonb03561f61302() 923 [](const FQName& fqName) { return fqName.getInterfacePassthroughName() + ".h"; },
924 astGenerationFunction(&AST::generatePassthroughHeader),
925 },
926 };
927
928 static const std::vector<FileGenerator> kCppSourceFormats = {
929 {
930 FileGenerator::alwaysGenerate,
__anonb03561f61402() 931 [](const FQName& fqName) {
932 return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + "All.cpp" : "types.cpp";
933 },
934 astGenerationFunction(&AST::generateCppSource),
935 },
936 };
937
938 static const std::vector<FileGenerator> kCppImplHeaderFormats = {
939 {
940 FileGenerator::generateForInterfaces,
__anonb03561f61502() 941 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".h"; },
942 astGenerationFunction(&AST::generateCppImplHeader),
943 },
944 };
945
946 static const std::vector<FileGenerator> kCppImplSourceFormats = {
947 {
948 FileGenerator::generateForInterfaces,
__anonb03561f61602() 949 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".cpp"; },
950 astGenerationFunction(&AST::generateCppImplSource),
951 },
952 };
953
954 static const std::vector<FileGenerator> kCppAdapterHeaderFormats = {
955 {
956 FileGenerator::alwaysGenerate,
__anonb03561f61702() 957 [](const FQName& fqName) {
958 return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".h" : "Atypes.h";
959 },
960 astGenerationFunction(&AST::generateCppAdapterHeader),
961 },
962 };
963
964 static const std::vector<FileGenerator> kCppAdapterSourceFormats = {
965 {
966 FileGenerator::alwaysGenerate,
__anonb03561f61802() 967 [](const FQName& fqName) {
968 return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".cpp" : "Atypes.cpp";
969 },
970 astGenerationFunction(&AST::generateCppAdapterSource),
971 },
972 };
973
974 static const std::vector<OutputHandler> kFormats = {
975 {
976 "check",
977 "Parses the interface to see if valid but doesn't write any files.",
978 OutputMode::NOT_NEEDED,
979 Coordinator::Location::STANDARD_OUT,
980 GenerationGranularity::PER_FILE,
981 validateForSource,
982 {
983 {
984 FileGenerator::alwaysGenerate,
985 nullptr /* filename for fqname */,
986 astGenerationFunction(),
987 },
988 },
989 },
990 {
991 "c++",
992 "(internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.",
993 OutputMode::NEEDS_DIR,
994 Coordinator::Location::GEN_OUTPUT,
995 GenerationGranularity::PER_FILE,
996 validateForSource,
997 kCppHeaderFormats + kCppSourceFormats,
998 },
999 {
1000 "c++-headers",
1001 "(internal) Generates C++ headers for interface files for talking to HIDL interfaces.",
1002 OutputMode::NEEDS_DIR,
1003 Coordinator::Location::GEN_OUTPUT,
1004 GenerationGranularity::PER_FILE,
1005 validateForSource,
1006 kCppHeaderFormats,
1007 },
1008 {
1009 "c++-sources",
1010 "(internal) Generates C++ sources for interface files for talking to HIDL interfaces.",
1011 OutputMode::NEEDS_DIR,
1012 Coordinator::Location::GEN_OUTPUT,
1013 GenerationGranularity::PER_FILE,
1014 validateForSource,
1015 kCppSourceFormats,
1016 },
1017 {
1018 "export-header",
1019 "Generates a header file from @export enumerations to help maintain legacy code.",
1020 OutputMode::NEEDS_FILE,
1021 Coordinator::Location::DIRECT,
1022 GenerationGranularity::PER_PACKAGE,
1023 validateIsPackage,
1024 {singleFileGenerator("", generateExportHeaderForPackage(false /* forJava */))}
1025 },
1026 {
1027 "c++-impl",
1028 "Generates boilerplate implementation of a hidl interface in C++ (for convenience).",
1029 OutputMode::NEEDS_DIR,
1030 Coordinator::Location::DIRECT,
1031 GenerationGranularity::PER_FILE,
1032 validateForSource,
1033 kCppImplHeaderFormats + kCppImplSourceFormats,
1034 },
1035 {
1036 "c++-impl-headers",
1037 "c++-impl but headers only",
1038 OutputMode::NEEDS_DIR,
1039 Coordinator::Location::DIRECT,
1040 GenerationGranularity::PER_FILE,
1041 validateForSource,
1042 kCppImplHeaderFormats,
1043 },
1044 {
1045 "c++-impl-sources",
1046 "c++-impl but sources only",
1047 OutputMode::NEEDS_DIR,
1048 Coordinator::Location::DIRECT,
1049 GenerationGranularity::PER_FILE,
1050 validateForSource,
1051 kCppImplSourceFormats,
1052 },
1053 {
1054 "c++-adapter",
1055 "Takes a x.(y+n) interface and mocks an x.y interface.",
1056 OutputMode::NEEDS_DIR,
1057 Coordinator::Location::GEN_OUTPUT,
1058 GenerationGranularity::PER_FILE,
1059 validateForSource,
1060 kCppAdapterHeaderFormats + kCppAdapterSourceFormats,
1061 },
1062 {
1063 "c++-adapter-headers",
1064 "c++-adapter but helper headers only",
1065 OutputMode::NEEDS_DIR,
1066 Coordinator::Location::GEN_OUTPUT,
1067 GenerationGranularity::PER_FILE,
1068 validateForSource,
1069 kCppAdapterHeaderFormats,
1070 },
1071 {
1072 "c++-adapter-sources",
1073 "c++-adapter but helper sources only",
1074 OutputMode::NEEDS_DIR,
1075 Coordinator::Location::GEN_OUTPUT,
1076 GenerationGranularity::PER_FILE,
1077 validateForSource,
1078 kCppAdapterSourceFormats,
1079 },
1080 {
1081 "c++-adapter-main",
1082 "c++-adapter but the adapter binary source only",
1083 OutputMode::NEEDS_DIR,
1084 Coordinator::Location::DIRECT,
1085 GenerationGranularity::PER_PACKAGE,
1086 validateIsPackage,
1087 {singleFileGenerator("main.cpp", generateAdapterMainSource)},
1088 },
1089 {
1090 "java",
1091 "(internal) Generates Java library for talking to HIDL interfaces in Java.",
1092 OutputMode::NEEDS_DIR,
1093 Coordinator::Location::GEN_SANITIZED,
1094 GenerationGranularity::PER_TYPE,
1095 validateForSource,
1096 {
1097 {
1098 FileGenerator::alwaysGenerate,
__anonb03561f61902() 1099 [](const FQName& fqName) {
1100 return StringHelper::LTrim(fqName.name(), "types.") + ".java";
1101 },
1102 generateJavaForPackage,
1103 },
1104 }
1105 },
1106 {
1107 "java-constants",
1108 "(internal) Like export-header but for Java (always created by -Lmakefile if @export exists).",
1109 OutputMode::NEEDS_DIR,
1110 Coordinator::Location::GEN_SANITIZED,
1111 GenerationGranularity::PER_PACKAGE,
1112 validateIsPackage,
1113 {singleFileGenerator("Constants.java", generateExportHeaderForPackage(true /* forJava */))}
1114 },
1115 {
1116 "vts",
1117 "(internal) Generates vts proto files for use in vtsd.",
1118 OutputMode::NEEDS_DIR,
1119 Coordinator::Location::GEN_OUTPUT,
1120 GenerationGranularity::PER_FILE,
1121 validateForSource,
1122 {
1123 {
1124 FileGenerator::alwaysGenerate,
__anonb03561f61a02() 1125 [](const FQName& fqName) {
1126 return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + ".vts" : "types.vts";
1127 },
1128 astGenerationFunction(&AST::generateVts),
1129 },
1130 }
1131 },
1132 {
1133 "makefile",
1134 "(removed) Used to generate makefiles for -Ljava and -Ljava-constants.",
1135 OutputMode::NEEDS_SRC,
1136 Coordinator::Location::PACKAGE_ROOT,
1137 GenerationGranularity::PER_PACKAGE,
__anonb03561f61b02() 1138 [](const FQName &, const Coordinator*, const std::string &) {
1139 fprintf(stderr, "ERROR: makefile output is not supported. Use -Landroidbp for all build file generation.\n");
1140 return false;
1141 },
__anonb03561f61c02() 1142 {},
1143 },
1144 {
1145 "androidbp",
1146 "(internal) Generates Soong bp files for -Lc++-headers, -Lc++-sources, -Ljava, -Ljava-constants, and -Lc++-adapter.",
1147 OutputMode::NEEDS_SRC,
1148 Coordinator::Location::PACKAGE_ROOT,
1149 GenerationGranularity::PER_PACKAGE,
1150 validateIsPackage,
1151 {singleFileGenerator("Android.bp", generateAndroidBpForPackage)},
1152 },
1153 {
1154 "androidbp-impl",
1155 "Generates boilerplate bp files for implementation created with -Lc++-impl.",
1156 OutputMode::NEEDS_DIR,
1157 Coordinator::Location::DIRECT,
1158 GenerationGranularity::PER_PACKAGE,
1159 validateIsPackage,
1160 {singleFileGenerator("Android.bp", generateAndroidBpImplForPackage)},
1161 },
1162 {
1163 "hash",
1164 "Prints hashes of interface in `current.txt` format to standard out.",
1165 OutputMode::NOT_NEEDED,
1166 Coordinator::Location::STANDARD_OUT,
1167 GenerationGranularity::PER_FILE,
1168 validateForSource,
1169 {
1170 {
1171 FileGenerator::alwaysGenerate,
1172 nullptr /* file name for fqName */,
1173 generateHashOutput,
1174 },
1175 }
1176 },
1177 };
1178 // clang-format on
1179
usage(const char * me)1180 static void usage(const char *me) {
1181 fprintf(stderr,
1182 "usage: %s [-p <root path>] -o <output path> -L <language> [-O <owner>] (-r <interface "
1183 "root>)+ [-v] [-d <depfile>] FQNAME...\n\n",
1184 me);
1185
1186 fprintf(stderr,
1187 "Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output.\n\n");
1188
1189 fprintf(stderr, " -h: Prints this menu.\n");
1190 fprintf(stderr, " -L <language>: The following options are available:\n");
1191 for (auto& e : kFormats) {
1192 fprintf(stderr, " %-16s: %s\n", e.name().c_str(), e.description().c_str());
1193 }
1194 fprintf(stderr, " -O <owner>: The owner of the module for -Landroidbp(-impl)?.\n");
1195 fprintf(stderr, " -o <output path>: Location to output files.\n");
1196 fprintf(stderr, " -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.\n");
1197 fprintf(stderr, " -r <package:path root>: E.g., android.hardware:hardware/interfaces.\n");
1198 fprintf(stderr, " -v: verbose output.\n");
1199 fprintf(stderr, " -d <depfile>: location of depfile to write to.\n");
1200 }
1201
1202 // hidl is intentionally leaky. Turn off LeakSanitizer by default.
__asan_default_options()1203 extern "C" const char *__asan_default_options() {
1204 return "detect_leaks=0";
1205 }
1206
main(int argc,char ** argv)1207 int main(int argc, char **argv) {
1208 const char *me = argv[0];
1209 if (argc == 1) {
1210 usage(me);
1211 exit(1);
1212 }
1213
1214 const OutputHandler* outputFormat = nullptr;
1215 Coordinator coordinator;
1216 std::string outputPath;
1217
1218 int res;
1219 while ((res = getopt(argc, argv, "hp:o:O:r:L:vd:")) >= 0) {
1220 switch (res) {
1221 case 'p': {
1222 if (!coordinator.getRootPath().empty()) {
1223 fprintf(stderr, "ERROR: -p <root path> can only be specified once.\n");
1224 exit(1);
1225 }
1226 coordinator.setRootPath(optarg);
1227 break;
1228 }
1229
1230 case 'v': {
1231 coordinator.setVerbose(true);
1232 break;
1233 }
1234
1235 case 'd': {
1236 coordinator.setDepFile(optarg);
1237 break;
1238 }
1239
1240 case 'o': {
1241 if (!outputPath.empty()) {
1242 fprintf(stderr, "ERROR: -o <output path> can only be specified once.\n");
1243 exit(1);
1244 }
1245 outputPath = optarg;
1246 break;
1247 }
1248
1249 case 'O': {
1250 if (!coordinator.getOwner().empty()) {
1251 fprintf(stderr, "ERROR: -O <owner> can only be specified once.\n");
1252 exit(1);
1253 }
1254 coordinator.setOwner(optarg);
1255 break;
1256 }
1257
1258 case 'r': {
1259 std::string val(optarg);
1260 auto index = val.find_first_of(':');
1261 if (index == std::string::npos) {
1262 fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
1263 exit(1);
1264 }
1265
1266 auto root = val.substr(0, index);
1267 auto path = val.substr(index + 1);
1268
1269 std::string error;
1270 status_t err = coordinator.addPackagePath(root, path, &error);
1271 if (err != OK) {
1272 fprintf(stderr, "%s\n", error.c_str());
1273 exit(1);
1274 }
1275
1276 break;
1277 }
1278
1279 case 'L': {
1280 if (outputFormat != nullptr) {
1281 fprintf(stderr,
1282 "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1283 outputFormat->name().c_str());
1284 exit(1);
1285 }
1286 for (auto& e : kFormats) {
1287 if (e.name() == optarg) {
1288 outputFormat = &e;
1289 break;
1290 }
1291 }
1292 if (outputFormat == nullptr) {
1293 fprintf(stderr,
1294 "ERROR: unrecognized -L option: \"%s\".\n",
1295 optarg);
1296 exit(1);
1297 }
1298 break;
1299 }
1300
1301 case '?':
1302 case 'h':
1303 default: {
1304 usage(me);
1305 exit(1);
1306 break;
1307 }
1308 }
1309 }
1310
1311 if (coordinator.getRootPath().empty()) {
1312 const char* ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
1313 if (ANDROID_BUILD_TOP != nullptr) {
1314 coordinator.setRootPath(ANDROID_BUILD_TOP);
1315 }
1316 }
1317
1318 if (outputFormat == nullptr) {
1319 fprintf(stderr,
1320 "ERROR: no -L option provided.\n");
1321 exit(1);
1322 }
1323
1324 argc -= optind;
1325 argv += optind;
1326
1327 if (argc == 0) {
1328 fprintf(stderr, "ERROR: no fqname specified.\n");
1329 usage(me);
1330 exit(1);
1331 }
1332
1333 // Valid options are now in argv[0] .. argv[argc - 1].
1334
1335 switch (outputFormat->mOutputMode) {
1336 case OutputMode::NEEDS_DIR:
1337 case OutputMode::NEEDS_FILE: {
1338 if (outputPath.empty()) {
1339 usage(me);
1340 exit(1);
1341 }
1342
1343 if (outputFormat->mOutputMode == OutputMode::NEEDS_DIR) {
1344 if (outputPath.back() != '/') {
1345 outputPath += "/";
1346 }
1347 }
1348 break;
1349 }
1350 case OutputMode::NEEDS_SRC: {
1351 if (outputPath.empty()) {
1352 outputPath = coordinator.getRootPath();
1353 }
1354 if (outputPath.back() != '/') {
1355 outputPath += "/";
1356 }
1357
1358 break;
1359 }
1360
1361 default:
1362 outputPath.clear(); // Unused.
1363 break;
1364 }
1365
1366 coordinator.setOutputPath(outputPath);
1367
1368 coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
1369 coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
1370 coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
1371 coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
1372
1373 for (int i = 0; i < argc; ++i) {
1374 FQName fqName;
1375 if (!FQName::parse(argv[i], &fqName)) {
1376 fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", argv[i]);
1377 exit(1);
1378 }
1379
1380 // Dump extra verbose output
1381 if (coordinator.isVerbose()) {
1382 status_t err =
1383 dumpDefinedButUnreferencedTypeNames(fqName.getPackageAndVersion(), &coordinator);
1384 if (err != OK) return err;
1385 }
1386
1387 if (!outputFormat->validate(fqName, &coordinator, outputFormat->name())) {
1388 fprintf(stderr,
1389 "ERROR: output handler failed.\n");
1390 exit(1);
1391 }
1392
1393 status_t err = outputFormat->generate(fqName, &coordinator);
1394 if (err != OK) exit(1);
1395
1396 err = outputFormat->writeDepFile(fqName, &coordinator);
1397 if (err != OK) exit(1);
1398 }
1399
1400 return 0;
1401 }
1402