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