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