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 // Keep the list of libs which are used by VNDK core libs and should be part of
502 // VNDK libs
503 static const std::vector<std::string> vndkLibs = {
504 "android.hardware.audio.common@2.0",
505 "android.hardware.configstore@1.0",
506 "android.hardware.configstore@1.1",
507 "android.hardware.graphics.allocator@2.0",
508 "android.hardware.graphics.allocator@3.0",
509 "android.hardware.graphics.allocator@4.0",
510 "android.hardware.graphics.bufferqueue@1.0",
511 "android.hardware.graphics.bufferqueue@2.0",
512 "android.hardware.media.bufferpool@2.0",
513 "android.hardware.media.omx@1.0",
514 "android.hardware.media@1.0",
515 "android.hardware.memtrack@1.0",
516 "android.hardware.soundtrigger@2.0",
517 "android.hidl.token@1.0",
518 "android.system.suspend@1.0",
519 };
520
isVndkCoreLib(const FQName & fqName)521 bool isVndkCoreLib(const FQName& fqName) {
522 return std::find(vndkLibs.begin(), vndkLibs.end(), fqName.string()) != vndkLibs.end();
523 }
524
hasVariantFile(const FQName & fqName,const Coordinator * coordinator,const std::string & fileName,bool * isVariant)525 status_t hasVariantFile(const FQName& fqName, const Coordinator* coordinator,
526 const std::string& fileName, bool* isVariant) {
527 const auto fileExists = [](const std::string& file) {
528 struct stat buf;
529 return stat(file.c_str(), &buf) == 0;
530 };
531
532 std::string path;
533 status_t err =
534 coordinator->getFilepath(fqName, Coordinator::Location::PACKAGE_ROOT, fileName, &path);
535 if (err != OK) return err;
536
537 const bool exists = fileExists(path);
538
539 if (exists) {
540 coordinator->onFileAccess(path, "r");
541 }
542
543 *isVariant = exists;
544 return OK;
545 }
546
isSystemExtPackage(const FQName & fqName,const Coordinator * coordinator,bool * isSystemExt)547 status_t isSystemExtPackage(const FQName& fqName, const Coordinator* coordinator,
548 bool* isSystemExt) {
549 return hasVariantFile(fqName, coordinator, ".hidl_for_system_ext", isSystemExt);
550 }
551
isOdmPackage(const FQName & fqName,const Coordinator * coordinator,bool * isOdm)552 status_t isOdmPackage(const FQName& fqName, const Coordinator* coordinator, bool* isOdm) {
553 return hasVariantFile(fqName, coordinator, ".hidl_for_odm", isOdm);
554 }
555
generateAdapterMainSource(const FQName & packageFQName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)556 static status_t generateAdapterMainSource(const FQName& packageFQName,
557 const Coordinator* coordinator,
558 const FileGenerator::GetFormatter& getFormatter) {
559 std::vector<FQName> packageInterfaces;
560 status_t err =
561 coordinator->appendPackageInterfacesToVector(packageFQName,
562 &packageInterfaces);
563 if (err != OK) {
564 return err;
565 }
566
567 // b/146223994: parse all interfaces
568 // - causes files to get read (filling out dep file)
569 // - avoid creating successful output for broken files
570 for (const FQName& fqName : packageInterfaces) {
571 AST* ast = coordinator->parse(fqName);
572 if (ast == nullptr) {
573 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
574 return UNKNOWN_ERROR;
575 }
576 }
577
578 Formatter out = getFormatter();
579 if (!out.isValid()) {
580 return UNKNOWN_ERROR;
581 }
582
583 out << "#include <hidladapter/HidlBinderAdapter.h>\n";
584
585 for (auto &interface : packageInterfaces) {
586 if (interface.name() == "types") {
587 continue;
588 }
589 AST::generateCppPackageInclude(out, interface, interface.getInterfaceAdapterName());
590 }
591
592 out << "int main(int argc, char** argv) ";
593 out.block([&] {
594 out << "return ::android::hardware::adapterMain<\n";
595 out.indent();
596 for (auto &interface : packageInterfaces) {
597 if (interface.name() == "types") {
598 continue;
599 }
600 out << interface.getInterfaceAdapterFqName().cppName();
601
602 if (&interface != &packageInterfaces.back()) {
603 out << ",\n";
604 }
605 }
606 out << ">(\"" << packageFQName.string() << "\", argc, argv);\n";
607 out.unindent();
608 }).endl();
609 return OK;
610 }
611
generateAndroidBpForPackage(const FQName & packageFQName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)612 static status_t generateAndroidBpForPackage(const FQName& packageFQName,
613 const Coordinator* coordinator,
614 const FileGenerator::GetFormatter& getFormatter) {
615 CHECK(!packageFQName.isFullyQualified() && packageFQName.name().empty());
616
617 std::vector<FQName> packageInterfaces;
618
619 status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
620
621 if (err != OK) {
622 return err;
623 }
624
625 std::set<FQName> importedPackagesHierarchy;
626 std::vector<const Type *> exportedTypes;
627 AST* typesAST = nullptr;
628
629 for (const auto& fqName : packageInterfaces) {
630 AST* ast = coordinator->parse(fqName);
631
632 if (ast == nullptr) {
633 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
634
635 return UNKNOWN_ERROR;
636 }
637
638 if (fqName.name() == "types") {
639 typesAST = ast;
640 }
641
642 ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
643 ast->appendToExportedTypesVector(&exportedTypes);
644 }
645
646 bool needsJavaCode = packageNeedsJavaCode(packageInterfaces, typesAST);
647
648 bool genJavaConstants = needsJavaCode && !exportedTypes.empty();
649
650 bool isJavaCompatible;
651 err = isPackageJavaCompatible(packageFQName, coordinator, &isJavaCompatible);
652 if (err != OK) return err;
653 bool genJavaLibrary = needsJavaCode && isJavaCompatible;
654
655 bool isCoreAndroid = isCoreAndroidPackage(packageFQName);
656
657 bool isVndkCore = isVndkCoreLib(packageFQName);
658 bool isVndkSp = isSystemProcessSupportedPackage(packageFQName);
659
660 bool isSystemExtHidl;
661 err = isSystemExtPackage(packageFQName, coordinator, &isSystemExtHidl);
662 if (err != OK) return err;
663 bool isSystemExt = isSystemExtHidl || !isCoreAndroid;
664
665 bool isForOdm;
666 err = isOdmPackage(packageFQName, coordinator, &isForOdm);
667 if (err != OK) return err;
668
669 std::string packageRoot;
670 err = coordinator->getPackageRoot(packageFQName, &packageRoot);
671 if (err != OK) return err;
672
673 Formatter out = getFormatter();
674 if (!out.isValid()) {
675 return UNKNOWN_ERROR;
676 }
677
678 out << "// This file is autogenerated by hidl-gen -Landroidbp.\n\n";
679
680 out << "hidl_interface ";
681 out.block([&] {
682 out << "name: \"" << makeLibraryName(packageFQName) << "\",\n";
683 if (!coordinator->getOwner().empty()) {
684 out << "owner: \"" << coordinator->getOwner() << "\",\n";
685 }
686 out << "root: \"" << packageRoot << "\",\n";
687 if (isVndkCore || isVndkSp) {
688 out << "vndk: ";
689 out.block([&]() {
690 out << "enabled: true,\n";
691 if (isVndkSp) {
692 out << "support_system_process: true,\n";
693 }
694 }) << ",\n";
695 }
696 if (isSystemExt) {
697 out << "system_ext_specific: true,\n";
698 }
699 if (isForOdm) {
700 out << "odm_available: true,\n";
701 }
702 (out << "srcs: [\n").indent([&] {
703 for (const auto& fqName : packageInterfaces) {
704 out << "\"" << fqName.name() << ".hal\",\n";
705 }
706 }) << "],\n";
707 if (!importedPackagesHierarchy.empty()) {
708 (out << "interfaces: [\n").indent([&] {
709 for (const auto& fqName : importedPackagesHierarchy) {
710 out << "\"" << fqName.string() << "\",\n";
711 }
712 }) << "],\n";
713 }
714 // Explicity call this out for developers.
715 out << "gen_java: " << (genJavaLibrary ? "true" : "false") << ",\n";
716 if (genJavaConstants) {
717 out << "gen_java_constants: true,\n";
718 }
719 }).endl();
720
721 return OK;
722 }
723
generateAndroidBpImplForPackage(const FQName & packageFQName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)724 static status_t generateAndroidBpImplForPackage(const FQName& packageFQName,
725 const Coordinator* coordinator,
726 const FileGenerator::GetFormatter& getFormatter) {
727 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
728
729 std::vector<FQName> packageInterfaces;
730
731 status_t err =
732 coordinator->appendPackageInterfacesToVector(packageFQName,
733 &packageInterfaces);
734
735 if (err != OK) {
736 return err;
737 }
738
739 std::set<FQName> importedPackages;
740
741 for (const auto &fqName : packageInterfaces) {
742 AST *ast = coordinator->parse(fqName);
743
744 if (ast == nullptr) {
745 fprintf(stderr,
746 "ERROR: Could not parse %s. Aborting.\n",
747 fqName.string().c_str());
748
749 return UNKNOWN_ERROR;
750 }
751
752 ast->getImportedPackages(&importedPackages);
753 }
754
755 Formatter out = getFormatter();
756 if (!out.isValid()) {
757 return UNKNOWN_ERROR;
758 }
759
760 out << "// FIXME: your file license if you have one\n\n";
761 out << "cc_library_shared {\n";
762 out.indent([&] {
763 out << "// FIXME: this should only be -impl for a passthrough hal.\n"
764 << "// In most cases, to convert this to a binderized implementation, you should:\n"
765 << "// - change '-impl' to '-service' here and make it a cc_binary instead of a\n"
766 << "// cc_library_shared.\n"
767 << "// - add a *.rc file for this module.\n"
768 << "// - delete HIDL_FETCH_I* functions.\n"
769 << "// - call configureRpcThreadpool and registerAsService on the instance.\n"
770 << "// You may also want to append '-impl/-service' with a specific identifier like\n"
771 << "// '-vendor' or '-<hardware identifier>' etc to distinguish it.\n";
772 out << "name: \"" << libraryName << "\",\n";
773 if (!coordinator->getOwner().empty()) {
774 out << "owner: \"" << coordinator->getOwner() << "\",\n";
775 }
776 out << "relative_install_path: \"hw\",\n";
777 if (coordinator->getOwner().empty()) {
778 out << "// FIXME: this should be 'vendor: true' for modules that will eventually be\n"
779 "// on AOSP.\n";
780 }
781 out << "proprietary: true,\n";
782 out << "srcs: [\n";
783 out.indent([&] {
784 for (const auto &fqName : packageInterfaces) {
785 if (fqName.name() == "types") {
786 continue;
787 }
788 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
789 }
790 });
791 out << "],\n"
792 << "shared_libs: [\n";
793 out.indent([&] {
794 out << "\"libhidlbase\",\n"
795 << "\"libutils\",\n"
796 << "\"" << makeLibraryName(packageFQName) << "\",\n";
797
798 for (const auto &importedPackage : importedPackages) {
799 if (isHidlTransportPackage(importedPackage)) {
800 continue;
801 }
802
803 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
804 }
805 });
806 out << "],\n";
807 });
808 out << "}\n";
809
810 return OK;
811 }
812
validateForSource(const FQName & fqName,const Coordinator * coordinator,const std::string & language)813 bool validateForSource(const FQName& fqName, const Coordinator* coordinator,
814 const std::string& language) {
815 if (fqName.package().empty()) {
816 fprintf(stderr, "ERROR: Expecting package name\n");
817 return false;
818 }
819
820 if (fqName.version().empty()) {
821 fprintf(stderr, "ERROR: Expecting package version\n");
822 return false;
823 }
824
825 const std::string &name = fqName.name();
826 if (!name.empty()) {
827 if (name.find('.') == std::string::npos) {
828 return true;
829 }
830
831 if (language != "java" || name.find("types.") != 0) {
832 // When generating java sources for "types.hal", output can be
833 // constrained to just one of the top-level types declared
834 // by using the extended syntax
835 // android.hardware.Foo@1.0::types.TopLevelTypeName.
836 // In all other cases (different language, not 'types') the dot
837 // notation in the name is illegal in this context.
838 return false;
839 }
840
841 return true;
842 }
843
844 if (language == "java") {
845 bool isJavaCompatible;
846 status_t err = isPackageJavaCompatible(fqName, coordinator, &isJavaCompatible);
847 if (err != OK) return false;
848
849 if (!isJavaCompatible) {
850 fprintf(stderr,
851 "ERROR: %s is not Java compatible. The Java backend does NOT support union "
852 "types. In addition, vectors of arrays are limited to at most one-dimensional "
853 "arrays and vectors of {vectors,interfaces,memory} are not supported.\n",
854 fqName.string().c_str());
855 return false;
856 }
857 }
858
859 return true;
860 }
861
validateForFormat(const FQName & fqName,const Coordinator * coordinator,const std::string & format)862 bool validateForFormat(const FQName& fqName, const Coordinator* coordinator,
863 const std::string& format) {
864 CHECK_EQ(format, "format");
865
866 if (!validateForSource(fqName, coordinator, format)) return false;
867
868 std::vector<FQName> packageInterfaces;
869
870 if (fqName.isFullyQualified()) {
871 packageInterfaces.push_back(fqName);
872 } else {
873 status_t err = coordinator->appendPackageInterfacesToVector(fqName, &packageInterfaces);
874 if (err != OK) return err;
875 }
876
877 bool destroysInformation = false;
878
879 for (const auto& fqName : packageInterfaces) {
880 AST* ast = coordinator->parse(fqName);
881
882 if (ast->getUnhandledComments().size() > 0) {
883 destroysInformation = true;
884 for (const auto& i : ast->getUnhandledComments()) {
885 std::cerr << "Unrecognized comment at " << i->location() << std::endl;
886 Formatter err(stderr);
887 err.indent();
888 i->emit(err);
889 err.unindent();
890 err.endl();
891 }
892 }
893 }
894
895 if (destroysInformation) {
896 std::cerr << "\nhidl-gen does not support comments at these locations, and formatting "
897 "the file would destroy them. HIDL doc comments need to be multiline comments "
898 "(/*...*/) before specific elements. This will also cause them to be emitted "
899 "in output files in the correct locations so that IDE users or people "
900 "inspecting generated source can see them in the correct location. Formatting "
901 "the file would destroy these comments.\n";
902 return false;
903 }
904
905 return true;
906 }
907
generateExportHeaderForPackage(bool forJava)908 FileGenerator::GenerationFunction generateExportHeaderForPackage(bool forJava) {
909 return [forJava](const FQName& packageFQName, const Coordinator* coordinator,
910 const FileGenerator::GetFormatter& getFormatter) -> status_t {
911 CHECK(!packageFQName.package().empty() && !packageFQName.version().empty() &&
912 packageFQName.name().empty());
913
914 std::vector<FQName> packageInterfaces;
915
916 status_t err = coordinator->appendPackageInterfacesToVector(
917 packageFQName, &packageInterfaces);
918
919 if (err != OK) {
920 return err;
921 }
922
923 std::vector<const Type *> exportedTypes;
924
925 for (const auto &fqName : packageInterfaces) {
926 AST *ast = coordinator->parse(fqName);
927
928 if (ast == nullptr) {
929 fprintf(stderr,
930 "ERROR: Could not parse %s. Aborting.\n",
931 fqName.string().c_str());
932
933 return UNKNOWN_ERROR;
934 }
935
936 ast->appendToExportedTypesVector(&exportedTypes);
937 }
938
939 if (exportedTypes.empty()) {
940 fprintf(stderr,
941 "ERROR: -Ljava-constants (Android.bp: gen_java_constants) requested for %s, "
942 "but no types declare @export.",
943 packageFQName.string().c_str());
944 return UNKNOWN_ERROR;
945 }
946
947 Formatter out = getFormatter();
948 if (!out.isValid()) {
949 return UNKNOWN_ERROR;
950 }
951
952 std::string packagePath;
953 err = coordinator->getPackagePath(packageFQName, false /* relative */,
954 false /* sanitized */, &packagePath);
955 if (err != OK) return err;
956
957 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
958 << "// Source: " << packageFQName.string() << "\n"
959 << "// Location: " << packagePath << "\n\n";
960
961 std::string guard;
962 if (forJava) {
963 out << "package " << packageFQName.javaPackage() << ";\n\n";
964 out << "public class Constants {\n";
965 out.indent();
966 } else {
967 guard = "HIDL_GENERATED_";
968 guard += StringHelper::Uppercase(packageFQName.tokenName());
969 guard += "_";
970 guard += "EXPORTED_CONSTANTS_H_";
971
972 out << "#ifndef "
973 << guard
974 << "\n#define "
975 << guard
976 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
977 }
978
979 for (const auto &type : exportedTypes) {
980 type->emitExportedHeader(out, forJava);
981 }
982
983 if (forJava) {
984 out.unindent();
985 out << "}\n";
986 } else {
987 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
988 << guard
989 << "\n";
990 }
991
992 return OK;
993 };
994 }
995
generateHashOutput(const FQName & fqName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)996 static status_t generateHashOutput(const FQName& fqName, const Coordinator* coordinator,
997 const FileGenerator::GetFormatter& getFormatter) {
998 CHECK(fqName.isFullyQualified());
999
1000 AST* ast = coordinator->parse(fqName, {} /* parsed */,
1001 Coordinator::Enforce::NO_HASH /* enforcement */);
1002
1003 if (ast == nullptr) {
1004 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
1005
1006 return UNKNOWN_ERROR;
1007 }
1008
1009 Formatter out = getFormatter();
1010 if (!out.isValid()) {
1011 return UNKNOWN_ERROR;
1012 }
1013
1014 out << Hash::getHash(ast->getFilename()).hexString() << " " << fqName.string() << "\n";
1015
1016 return OK;
1017 }
1018
generateFunctionCount(const FQName & fqName,const Coordinator * coordinator,const FileGenerator::GetFormatter & getFormatter)1019 static status_t generateFunctionCount(const FQName& fqName, const Coordinator* coordinator,
1020 const FileGenerator::GetFormatter& getFormatter) {
1021 CHECK(fqName.isFullyQualified());
1022
1023 AST* ast = coordinator->parse(fqName, {} /* parsed */,
1024 Coordinator::Enforce::NO_HASH /* enforcement */);
1025
1026 if (ast == nullptr) {
1027 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
1028 return UNKNOWN_ERROR;
1029 }
1030
1031 const Interface* interface = ast->getInterface();
1032 if (interface == nullptr) {
1033 fprintf(stderr, "ERROR: Function count requires interface: %s.\n", fqName.string().c_str());
1034 return UNKNOWN_ERROR;
1035 }
1036
1037 Formatter out = getFormatter();
1038 if (!out.isValid()) {
1039 return UNKNOWN_ERROR;
1040 }
1041
1042 // This is wrong for android.hidl.base@1.0::IBase, but in that case, it doesn't matter.
1043 // This is just the number of APIs that are added.
1044 out << fqName.string() << " " << interface->userDefinedMethods().size() << "\n";
1045
1046 return OK;
1047 }
1048
1049 template <typename T>
operator +(const std::vector<T> & lhs,const std::vector<T> & rhs)1050 std::vector<T> operator+(const std::vector<T>& lhs, const std::vector<T>& rhs) {
1051 std::vector<T> ret;
1052 ret.reserve(lhs.size() + rhs.size());
1053 ret.insert(ret.begin(), lhs.begin(), lhs.end());
1054 ret.insert(ret.end(), rhs.begin(), rhs.end());
1055 return ret;
1056 }
1057
1058 // clang-format off
1059 static const std::vector<FileGenerator> kCppHeaderFormats = {
1060 {
1061 FileGenerator::alwaysGenerate,
__anon226c43a00e02() 1062 [](const FQName& fqName) { return fqName.name() + ".h"; },
1063 astGenerationFunction(&AST::generateInterfaceHeader),
1064 },
1065 {
1066 FileGenerator::alwaysGenerate,
__anon226c43a00f02() 1067 [](const FQName& fqName) {
1068 return fqName.isInterfaceName() ? fqName.getInterfaceHwName() + ".h" : "hwtypes.h";
1069 },
1070 astGenerationFunction(&AST::generateHwBinderHeader),
1071 },
1072 {
1073 FileGenerator::generateForInterfaces,
__anon226c43a01002() 1074 [](const FQName& fqName) { return fqName.getInterfaceStubName() + ".h"; },
1075 astGenerationFunction(&AST::generateStubHeader),
1076 },
1077 {
1078 FileGenerator::generateForInterfaces,
__anon226c43a01102() 1079 [](const FQName& fqName) { return fqName.getInterfaceProxyName() + ".h"; },
1080 astGenerationFunction(&AST::generateProxyHeader),
1081 },
1082 {
1083 FileGenerator::generateForInterfaces,
__anon226c43a01202() 1084 [](const FQName& fqName) { return fqName.getInterfacePassthroughName() + ".h"; },
1085 astGenerationFunction(&AST::generatePassthroughHeader),
1086 },
1087 };
1088
1089 static const std::vector<FileGenerator> kCppSourceFormats = {
1090 {
1091 FileGenerator::alwaysGenerate,
__anon226c43a01302() 1092 [](const FQName& fqName) {
1093 return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + "All.cpp" : "types.cpp";
1094 },
1095 astGenerationFunction(&AST::generateCppSource),
1096 },
1097 };
1098
1099 static const std::vector<FileGenerator> kCppImplHeaderFormats = {
1100 {
1101 FileGenerator::generateForInterfaces,
__anon226c43a01402() 1102 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".h"; },
1103 astGenerationFunction(&AST::generateCppImplHeader),
1104 },
1105 };
1106
1107 static const std::vector<FileGenerator> kCppImplSourceFormats = {
1108 {
1109 FileGenerator::generateForInterfaces,
__anon226c43a01502() 1110 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".cpp"; },
1111 astGenerationFunction(&AST::generateCppImplSource),
1112 },
1113 };
1114
1115 static const std::vector<FileGenerator> kCppAdapterHeaderFormats = {
1116 {
1117 FileGenerator::alwaysGenerate,
__anon226c43a01602() 1118 [](const FQName& fqName) {
1119 return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".h" : "Atypes.h";
1120 },
1121 astGenerationFunction(&AST::generateCppAdapterHeader),
1122 },
1123 };
1124
1125 static const std::vector<FileGenerator> kCppAdapterSourceFormats = {
1126 {
1127 FileGenerator::alwaysGenerate,
__anon226c43a01702() 1128 [](const FQName& fqName) {
1129 return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".cpp" : "Atypes.cpp";
1130 },
1131 astGenerationFunction(&AST::generateCppAdapterSource),
1132 },
1133 };
1134
1135 static const std::vector<OutputHandler> kFormats = {
1136 {
1137 "check",
1138 "Parses the interface to see if valid but doesn't write any files.",
1139 OutputMode::NOT_NEEDED,
1140 Coordinator::Location::STANDARD_OUT,
1141 GenerationGranularity::PER_FILE,
1142 validateForSource,
1143 {
1144 {
1145 FileGenerator::alwaysGenerate,
1146 nullptr /* filename for fqname */,
1147 astGenerationFunction(),
1148 },
1149 },
1150 },
1151 {
1152 "c++",
1153 "(internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.",
1154 OutputMode::NEEDS_DIR,
1155 Coordinator::Location::GEN_OUTPUT,
1156 GenerationGranularity::PER_FILE,
1157 validateForSource,
1158 kCppHeaderFormats + kCppSourceFormats,
1159 },
1160 {
1161 "c++-headers",
1162 "(internal) Generates C++ headers for interface files for talking to HIDL interfaces.",
1163 OutputMode::NEEDS_DIR,
1164 Coordinator::Location::GEN_OUTPUT,
1165 GenerationGranularity::PER_FILE,
1166 validateForSource,
1167 kCppHeaderFormats,
1168 },
1169 {
1170 "c++-sources",
1171 "(internal) Generates C++ sources for interface files for talking to HIDL interfaces.",
1172 OutputMode::NEEDS_DIR,
1173 Coordinator::Location::GEN_OUTPUT,
1174 GenerationGranularity::PER_FILE,
1175 validateForSource,
1176 kCppSourceFormats,
1177 },
1178 {
1179 "export-header",
1180 "Generates a header file from @export enumerations to help maintain legacy code.",
1181 OutputMode::NEEDS_FILE,
1182 Coordinator::Location::DIRECT,
1183 GenerationGranularity::PER_PACKAGE,
1184 validateIsPackage,
1185 {singleFileGenerator("", generateExportHeaderForPackage(false /* forJava */))}
1186 },
1187 {
1188 "c++-impl",
1189 "Generates boilerplate implementation of a hidl interface in C++ (for convenience).",
1190 OutputMode::NEEDS_DIR,
1191 Coordinator::Location::DIRECT,
1192 GenerationGranularity::PER_FILE,
1193 validateForSource,
1194 kCppImplHeaderFormats + kCppImplSourceFormats,
1195 },
1196 {
1197 "c++-impl-headers",
1198 "c++-impl but headers only.",
1199 OutputMode::NEEDS_DIR,
1200 Coordinator::Location::DIRECT,
1201 GenerationGranularity::PER_FILE,
1202 validateForSource,
1203 kCppImplHeaderFormats,
1204 },
1205 {
1206 "c++-impl-sources",
1207 "c++-impl but sources only.",
1208 OutputMode::NEEDS_DIR,
1209 Coordinator::Location::DIRECT,
1210 GenerationGranularity::PER_FILE,
1211 validateForSource,
1212 kCppImplSourceFormats,
1213 },
1214 {
1215 "c++-adapter",
1216 "Takes a x.(y+n) interface and mocks an x.y interface.",
1217 OutputMode::NEEDS_DIR,
1218 Coordinator::Location::GEN_OUTPUT,
1219 GenerationGranularity::PER_FILE,
1220 validateForSource,
1221 kCppAdapterHeaderFormats + kCppAdapterSourceFormats,
1222 },
1223 {
1224 "c++-adapter-headers",
1225 "c++-adapter but helper headers only.",
1226 OutputMode::NEEDS_DIR,
1227 Coordinator::Location::GEN_OUTPUT,
1228 GenerationGranularity::PER_FILE,
1229 validateForSource,
1230 kCppAdapterHeaderFormats,
1231 },
1232 {
1233 "c++-adapter-sources",
1234 "c++-adapter but helper sources only.",
1235 OutputMode::NEEDS_DIR,
1236 Coordinator::Location::GEN_OUTPUT,
1237 GenerationGranularity::PER_FILE,
1238 validateForSource,
1239 kCppAdapterSourceFormats,
1240 },
1241 {
1242 "c++-adapter-main",
1243 "c++-adapter but the adapter binary source only.",
1244 OutputMode::NEEDS_DIR,
1245 Coordinator::Location::DIRECT,
1246 GenerationGranularity::PER_PACKAGE,
1247 validateIsPackage,
1248 {singleFileGenerator("main.cpp", generateAdapterMainSource)},
1249 },
1250 {
1251 "java",
1252 "(internal) Generates Java library for talking to HIDL interfaces in Java.",
1253 OutputMode::NEEDS_DIR,
1254 Coordinator::Location::GEN_SANITIZED,
1255 GenerationGranularity::PER_TYPE,
1256 validateForSource,
1257 {
1258 {
1259 FileGenerator::alwaysGenerate,
__anon226c43a01802() 1260 [](const FQName& fqName) {
1261 return StringHelper::LTrim(fqName.name(), "types.") + ".java";
1262 },
1263 generateJavaForPackage,
1264 },
1265 }
1266 },
1267 {
1268 "java-impl",
1269 "Generates boilerplate implementation of a hidl interface in Java (for convenience).",
1270 OutputMode::NEEDS_DIR,
1271 Coordinator::Location::DIRECT,
1272 GenerationGranularity::PER_FILE,
1273 validateForSource,
1274 {
1275 {
1276 FileGenerator::generateForInterfaces,
__anon226c43a01902() 1277 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".java"; },
1278 astGenerationFunction(&AST::generateJavaImpl),
1279 },
1280 }
1281 },
1282 {
1283 "java-constants",
1284 "(internal) Like export-header but for Java (always created by -Lmakefile if @export exists).",
1285 OutputMode::NEEDS_DIR,
1286 Coordinator::Location::GEN_SANITIZED,
1287 GenerationGranularity::PER_PACKAGE,
1288 validateIsPackage,
1289 {singleFileGenerator("Constants.java", generateExportHeaderForPackage(true /* forJava */))}
1290 },
1291 {
1292 "vts",
1293 "(internal) Generates vts proto files for use in vtsd.",
1294 OutputMode::NEEDS_DIR,
1295 Coordinator::Location::GEN_OUTPUT,
1296 GenerationGranularity::PER_FILE,
1297 validateForSource,
1298 {
1299 {
1300 FileGenerator::alwaysGenerate,
__anon226c43a01a02() 1301 [](const FQName& fqName) {
1302 return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + ".vts" : "types.vts";
1303 },
1304 astGenerationFunction(&AST::generateVts),
1305 },
1306 }
1307 },
1308 {
1309 "makefile",
1310 "(removed) Used to generate makefiles for -Ljava and -Ljava-constants.",
1311 OutputMode::NEEDS_SRC,
1312 Coordinator::Location::PACKAGE_ROOT,
1313 GenerationGranularity::PER_PACKAGE,
__anon226c43a01b02() 1314 [](const FQName &, const Coordinator*, const std::string &) {
1315 fprintf(stderr, "ERROR: makefile output is not supported. Use -Landroidbp for all build file generation.\n");
1316 return false;
1317 },
__anon226c43a01c02() 1318 {},
1319 },
1320 {
1321 "androidbp",
1322 "(internal) Generates Soong bp files for -Lc++-headers, -Lc++-sources, -Ljava, -Ljava-constants, and -Lc++-adapter.",
1323 OutputMode::NEEDS_SRC,
1324 Coordinator::Location::PACKAGE_ROOT,
1325 GenerationGranularity::PER_PACKAGE,
1326 validateIsPackage,
1327 {singleFileGenerator("Android.bp", generateAndroidBpForPackage)},
1328 },
1329 {
1330 "androidbp-impl",
1331 "Generates boilerplate bp files for implementation created with -Lc++-impl.",
1332 OutputMode::NEEDS_DIR,
1333 Coordinator::Location::DIRECT,
1334 GenerationGranularity::PER_PACKAGE,
1335 validateIsPackage,
1336 {singleFileGenerator("Android.bp", generateAndroidBpImplForPackage)},
1337 },
1338 {
1339 "hash",
1340 "Prints hashes of interface in `current.txt` format to standard out.",
1341 OutputMode::NOT_NEEDED,
1342 Coordinator::Location::STANDARD_OUT,
1343 GenerationGranularity::PER_FILE,
1344 validateForSource,
1345 {
1346 {
1347 FileGenerator::alwaysGenerate,
1348 nullptr /* file name for fqName */,
1349 generateHashOutput,
1350 },
1351 }
1352 },
1353 {
1354 "function-count",
1355 "Prints the total number of functions added by the package or interface.",
1356 OutputMode::NOT_NEEDED,
1357 Coordinator::Location::STANDARD_OUT,
1358 GenerationGranularity::PER_FILE,
1359 validateForSource,
1360 {
1361 {
1362 FileGenerator::generateForInterfaces,
1363 nullptr /* file name for fqName */,
1364 generateFunctionCount,
1365 },
1366 }
1367 },
1368 {
1369 "dependencies",
1370 "Prints all depended types.",
1371 OutputMode::NOT_NEEDED,
1372 Coordinator::Location::STANDARD_OUT,
1373 GenerationGranularity::PER_FILE,
1374 validateForSource,
1375 {
1376 {
1377 FileGenerator::alwaysGenerate,
1378 nullptr /* file name for fqName */,
1379 astGenerationFunction(&AST::generateDependencies),
1380 },
1381 },
1382 },
1383 {
1384 "inheritance-hierarchy",
1385 "Prints the hierarchy of inherited types as a JSON object.",
1386 OutputMode::NOT_NEEDED,
1387 Coordinator::Location::STANDARD_OUT,
1388 GenerationGranularity::PER_FILE,
1389 validateForSource,
1390 {
1391 {
1392 FileGenerator::alwaysGenerate,
1393 nullptr /* file name for fqName */,
1394 astGenerationFunction(&AST::generateInheritanceHierarchy),
1395 },
1396 },
1397 },
1398 {
1399 "format",
1400 "Reformats the .hal files",
1401 OutputMode::NEEDS_SRC,
1402 Coordinator::Location::PACKAGE_ROOT,
1403 GenerationGranularity::PER_FILE,
1404 validateForFormat,
1405 {
1406 {
1407 FileGenerator::alwaysGenerate,
__anon226c43a01d02() 1408 [](const FQName& fqName) { return fqName.name() + ".hal"; },
1409 astGenerationFunction(&AST::generateFormattedHidl),
1410 },
1411 }
1412 },
1413 };
1414 // clang-format on
1415
usage(const char * me)1416 static void usage(const char* me) {
1417 Formatter out(stderr);
1418
1419 out << "Usage: " << me << " -o <output path> -L <language> [-O <owner>] ";
1420 Coordinator::emitOptionsUsageString(out);
1421 out << " FQNAME...\n\n";
1422
1423 out << "Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output.\n\n";
1424
1425 out.indent();
1426 out.indent();
1427
1428 out << "-h: Prints this menu.\n";
1429 out << "-L <language>: The following options are available:\n";
1430 out.indent([&] {
1431 for (auto& e : kFormats) {
1432 std::stringstream sstream;
1433 sstream.fill(' ');
1434 sstream.width(16);
1435 sstream << std::left << e.name();
1436
1437 out << sstream.str() << ": " << e.description() << "\n";
1438 }
1439 });
1440 out << "-O <owner>: The owner of the module for -Landroidbp(-impl)?.\n";
1441 out << "-o <output path>: Location to output files.\n";
1442 Coordinator::emitOptionsDetailString(out);
1443
1444 out.unindent();
1445 out.unindent();
1446 }
1447
1448 // hidl is intentionally leaky. Turn off LeakSanitizer by default.
__asan_default_options()1449 extern "C" const char *__asan_default_options() {
1450 return "detect_leaks=0";
1451 }
1452
main(int argc,char ** argv)1453 int main(int argc, char **argv) {
1454 const char *me = argv[0];
1455 if (argc == 1) {
1456 usage(me);
1457 exit(1);
1458 }
1459
1460 const OutputHandler* outputFormat = nullptr;
1461 Coordinator coordinator;
1462 std::string outputPath;
1463
1464 coordinator.parseOptions(argc, argv, "ho:O:L:", [&](int res, char* arg) {
1465 switch (res) {
1466 case 'o': {
1467 if (!outputPath.empty()) {
1468 fprintf(stderr, "ERROR: -o <output path> can only be specified once.\n");
1469 exit(1);
1470 }
1471 outputPath = arg;
1472 break;
1473 }
1474
1475 case 'O': {
1476 if (!coordinator.getOwner().empty()) {
1477 fprintf(stderr, "ERROR: -O <owner> can only be specified once.\n");
1478 exit(1);
1479 }
1480 coordinator.setOwner(arg);
1481 break;
1482 }
1483
1484 case 'L': {
1485 if (outputFormat != nullptr) {
1486 fprintf(stderr,
1487 "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1488 outputFormat->name().c_str());
1489 exit(1);
1490 }
1491 for (auto& e : kFormats) {
1492 if (e.name() == arg) {
1493 outputFormat = &e;
1494 break;
1495 }
1496 }
1497 if (outputFormat == nullptr) {
1498 fprintf(stderr, "ERROR: unrecognized -L option: \"%s\".\n", arg);
1499 exit(1);
1500 }
1501 break;
1502 }
1503
1504 case '?':
1505 case 'h':
1506 default: {
1507 usage(me);
1508 exit(1);
1509 break;
1510 }
1511 }
1512 });
1513
1514 if (outputFormat == nullptr) {
1515 fprintf(stderr,
1516 "ERROR: no -L option provided.\n");
1517 exit(1);
1518 }
1519
1520 argc -= optind;
1521 argv += optind;
1522
1523 if (argc == 0) {
1524 fprintf(stderr, "ERROR: no fqname specified.\n");
1525 usage(me);
1526 exit(1);
1527 }
1528
1529 // Valid options are now in argv[0] .. argv[argc - 1].
1530
1531 switch (outputFormat->mOutputMode) {
1532 case OutputMode::NEEDS_DIR:
1533 case OutputMode::NEEDS_FILE: {
1534 if (outputPath.empty()) {
1535 usage(me);
1536 exit(1);
1537 }
1538
1539 if (outputFormat->mOutputMode == OutputMode::NEEDS_DIR) {
1540 if (outputPath.back() != '/') {
1541 outputPath += "/";
1542 }
1543 }
1544 break;
1545 }
1546 case OutputMode::NEEDS_SRC: {
1547 if (outputPath.empty()) {
1548 outputPath = coordinator.getRootPath();
1549 }
1550 if (outputPath.back() != '/') {
1551 outputPath += "/";
1552 }
1553
1554 break;
1555 }
1556
1557 default:
1558 outputPath.clear(); // Unused.
1559 break;
1560 }
1561
1562 coordinator.setOutputPath(outputPath);
1563
1564 for (int i = 0; i < argc; ++i) {
1565 const char* arg = argv[i];
1566
1567 FQName fqName;
1568 if (!FQName::parse(arg, &fqName)) {
1569 fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", arg);
1570 exit(1);
1571 }
1572
1573 if (coordinator.getPackageInterfaceFiles(fqName, nullptr /*fileNames*/) != OK) {
1574 fprintf(stderr, "ERROR: Could not get sources for %s.\n", arg);
1575 exit(1);
1576 }
1577
1578 // Dump extra verbose output
1579 if (coordinator.isVerbose()) {
1580 status_t err =
1581 dumpDefinedButUnreferencedTypeNames(fqName.getPackageAndVersion(), &coordinator);
1582 if (err != OK) return err;
1583 }
1584
1585 if (!outputFormat->validate(fqName, &coordinator, outputFormat->name())) {
1586 fprintf(stderr, "ERROR: Validation failed.\n");
1587 exit(1);
1588 }
1589
1590 status_t err = outputFormat->generate(fqName, &coordinator);
1591 if (err != OK) exit(1);
1592
1593 err = outputFormat->writeDepFile(fqName, &coordinator);
1594 if (err != OK) exit(1);
1595 }
1596
1597 return 0;
1598 }
1599