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