1 /* 2 * Copyright (C) 2015, 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 "aidl.h" 18 19 #include <fcntl.h> 20 #include <iostream> 21 #include <map> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/param.h> 26 #include <sys/stat.h> 27 #include <unistd.h> 28 29 #ifdef _WIN32 30 #include <io.h> 31 #include <direct.h> 32 #include <sys/stat.h> 33 #endif 34 35 #include <android-base/strings.h> 36 37 #include "aidl_language.h" 38 #include "generate_cpp.h" 39 #include "generate_java.h" 40 #include "import_resolver.h" 41 #include "logging.h" 42 #include "options.h" 43 #include "os.h" 44 #include "type_cpp.h" 45 #include "type_java.h" 46 #include "type_namespace.h" 47 48 #ifndef O_BINARY 49 # define O_BINARY 0 50 #endif 51 52 using android::base::Join; 53 using android::base::Split; 54 using std::cerr; 55 using std::endl; 56 using std::map; 57 using std::set; 58 using std::string; 59 using std::unique_ptr; 60 using std::vector; 61 62 namespace android { 63 namespace aidl { 64 namespace { 65 66 // The following are gotten as the offset from the allowable id's between 67 // android.os.IBinder.FIRST_CALL_TRANSACTION=1 and 68 // android.os.IBinder.LAST_CALL_TRANSACTION=16777215 69 const int kMinUserSetMethodId = 0; 70 const int kMaxUserSetMethodId = 16777214; 71 72 bool check_filename(const std::string& filename, 73 const std::string& package, 74 const std::string& name, 75 unsigned line) { 76 const char* p; 77 string expected; 78 string fn; 79 size_t len; 80 bool valid = false; 81 82 if (!IoDelegate::GetAbsolutePath(filename, &fn)) { 83 return false; 84 } 85 86 if (!package.empty()) { 87 expected = package; 88 expected += '.'; 89 } 90 91 len = expected.length(); 92 for (size_t i=0; i<len; i++) { 93 if (expected[i] == '.') { 94 expected[i] = OS_PATH_SEPARATOR; 95 } 96 } 97 98 expected.append(name, 0, name.find('.')); 99 100 expected += ".aidl"; 101 102 len = fn.length(); 103 valid = (len >= expected.length()); 104 105 if (valid) { 106 p = fn.c_str() + (len - expected.length()); 107 108 #ifdef _WIN32 109 if (OS_PATH_SEPARATOR != '/') { 110 // Input filename under cygwin most likely has / separators 111 // whereas the expected string uses \\ separators. Adjust 112 // them accordingly. 113 for (char *c = const_cast<char *>(p); *c; ++c) { 114 if (*c == '/') *c = OS_PATH_SEPARATOR; 115 } 116 } 117 #endif 118 119 // aidl assumes case-insensitivity on Mac Os and Windows. 120 #if defined(__linux__) 121 valid = (expected == p); 122 #else 123 valid = !strcasecmp(expected.c_str(), p); 124 #endif 125 } 126 127 if (!valid) { 128 fprintf(stderr, "%s:%d interface %s should be declared in a file" 129 " called %s.\n", 130 filename.c_str(), line, name.c_str(), expected.c_str()); 131 } 132 133 return valid; 134 } 135 136 bool check_filenames(const std::string& filename, const AidlDocument* doc) { 137 if (!doc) 138 return true; 139 140 const AidlInterface* interface = doc->GetInterface(); 141 142 if (interface) { 143 return check_filename(filename, interface->GetPackage(), 144 interface->GetName(), interface->GetLine()); 145 } 146 147 bool success = true; 148 149 for (const auto& item : doc->GetParcelables()) { 150 success &= check_filename(filename, item->GetPackage(), item->GetName(), 151 item->GetLine()); 152 } 153 154 return success; 155 } 156 157 bool gather_types(const std::string& filename, 158 const AidlDocument* doc, 159 TypeNamespace* types) { 160 bool success = true; 161 162 const AidlInterface* interface = doc->GetInterface(); 163 164 if (interface) 165 return types->AddBinderType(*interface, filename); 166 167 for (const auto& item : doc->GetParcelables()) { 168 success &= types->AddParcelableType(*item, filename); 169 } 170 171 return success; 172 } 173 174 int check_types(const string& filename, 175 const AidlInterface* c, 176 TypeNamespace* types) { 177 int err = 0; 178 179 // Has to be a pointer due to deleting copy constructor. No idea why. 180 map<string, const AidlMethod*> method_names; 181 for (const auto& m : c->GetMethods()) { 182 bool oneway = m->IsOneway() || c->IsOneway(); 183 184 if (!types->MaybeAddContainerType(m->GetType())) { 185 err = 1; // return type is invalid 186 } 187 188 const ValidatableType* return_type = 189 types->GetReturnType(m->GetType(), filename); 190 191 if (!return_type) { 192 err = 1; 193 } 194 195 m->GetMutableType()->SetLanguageType(return_type); 196 197 if (oneway && m->GetType().GetName() != "void") { 198 cerr << filename << ":" << m->GetLine() 199 << " oneway method '" << m->GetName() << "' cannot return a value" 200 << endl; 201 err = 1; 202 } 203 204 int index = 1; 205 for (const auto& arg : m->GetArguments()) { 206 if (!types->MaybeAddContainerType(arg->GetType())) { 207 err = 1; 208 } 209 210 const ValidatableType* arg_type = 211 types->GetArgType(*arg, index, filename); 212 213 if (!arg_type) { 214 err = 1; 215 } 216 217 arg->GetMutableType()->SetLanguageType(arg_type); 218 219 if (oneway && arg->IsOut()) { 220 cerr << filename << ":" << m->GetLine() 221 << " oneway method '" << m->GetName() 222 << "' cannot have out parameters" << endl; 223 err = 1; 224 } 225 } 226 227 auto it = method_names.find(m->GetName()); 228 // prevent duplicate methods 229 if (it == method_names.end()) { 230 method_names[m->GetName()] = m.get(); 231 } else { 232 cerr << filename << ":" << m->GetLine() 233 << " attempt to redefine method " << m->GetName() << "," << endl 234 << filename << ":" << it->second->GetLine() 235 << " previously defined here." << endl; 236 err = 1; 237 } 238 } 239 return err; 240 } 241 242 void write_common_dep_file(const string& output_file, 243 const vector<string>& aidl_sources, 244 CodeWriter* writer) { 245 // Encode that the output file depends on aidl input files. 246 writer->Write("%s : \\\n", output_file.c_str()); 247 writer->Write(" %s", Join(aidl_sources, " \\\n ").c_str()); 248 writer->Write("\n\n"); 249 250 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file 251 // has been deleted, moved or renamed in incremental build. 252 for (const auto& src : aidl_sources) { 253 writer->Write("%s :\n", src.c_str()); 254 } 255 } 256 257 bool write_java_dep_file(const JavaOptions& options, 258 const vector<unique_ptr<AidlImport>>& imports, 259 const IoDelegate& io_delegate, 260 const string& output_file_name) { 261 string dep_file_name = options.DependencyFilePath(); 262 if (dep_file_name.empty()) { 263 return true; // nothing to do 264 } 265 CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name); 266 if (!writer) { 267 LOG(ERROR) << "Could not open dependency file: " << dep_file_name; 268 return false; 269 } 270 271 vector<string> source_aidl = {options.input_file_name_}; 272 for (const auto& import : imports) { 273 if (!import->GetFilename().empty()) { 274 source_aidl.push_back(import->GetFilename()); 275 } 276 } 277 278 write_common_dep_file(output_file_name, source_aidl, writer.get()); 279 280 return true; 281 } 282 283 bool write_cpp_dep_file(const CppOptions& options, 284 const AidlInterface& interface, 285 const vector<unique_ptr<AidlImport>>& imports, 286 const IoDelegate& io_delegate) { 287 using ::android::aidl::cpp::HeaderFile; 288 using ::android::aidl::cpp::ClassNames; 289 290 string dep_file_name = options.DependencyFilePath(); 291 if (dep_file_name.empty()) { 292 return true; // nothing to do 293 } 294 CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name); 295 if (!writer) { 296 LOG(ERROR) << "Could not open dependency file: " << dep_file_name; 297 return false; 298 } 299 300 vector<string> source_aidl = {options.InputFileName()}; 301 for (const auto& import : imports) { 302 if (!import->GetFilename().empty()) { 303 source_aidl.push_back(import->GetFilename()); 304 } 305 } 306 307 vector<string> headers; 308 for (ClassNames c : {ClassNames::CLIENT, 309 ClassNames::SERVER, 310 ClassNames::INTERFACE}) { 311 headers.push_back(options.OutputHeaderDir() + '/' + 312 HeaderFile(interface, c, false /* use_os_sep */)); 313 } 314 315 write_common_dep_file(options.OutputCppFilePath(), source_aidl, writer.get()); 316 writer->Write("\n"); 317 318 // Generated headers also depend on the source aidl files. 319 writer->Write("%s : \\\n %s\n", Join(headers, " \\\n ").c_str(), 320 Join(source_aidl, " \\\n ").c_str()); 321 322 return true; 323 } 324 325 string generate_outputFileName(const JavaOptions& options, 326 const AidlInterface& interface) { 327 string name = interface.GetName(); 328 string package = interface.GetPackage(); 329 string result; 330 331 // create the path to the destination folder based on the 332 // interface package name 333 result = options.output_base_folder_; 334 result += OS_PATH_SEPARATOR; 335 336 string packageStr = package; 337 size_t len = packageStr.length(); 338 for (size_t i=0; i<len; i++) { 339 if (packageStr[i] == '.') { 340 packageStr[i] = OS_PATH_SEPARATOR; 341 } 342 } 343 344 result += packageStr; 345 346 // add the filename by replacing the .aidl extension to .java 347 result += OS_PATH_SEPARATOR; 348 result.append(name, 0, name.find('.')); 349 result += ".java"; 350 351 return result; 352 } 353 354 int check_and_assign_method_ids(const char * filename, 355 const std::vector<std::unique_ptr<AidlMethod>>& items) { 356 // Check whether there are any methods with manually assigned id's and any that are not. 357 // Either all method id's must be manually assigned or all of them must not. 358 // Also, check for duplicates of user set id's and that the id's are within the proper bounds. 359 set<int> usedIds; 360 bool hasUnassignedIds = false; 361 bool hasAssignedIds = false; 362 for (const auto& item : items) { 363 if (item->HasId()) { 364 hasAssignedIds = true; 365 // Ensure that the user set id is not duplicated. 366 if (usedIds.find(item->GetId()) != usedIds.end()) { 367 // We found a duplicate id, so throw an error. 368 fprintf(stderr, 369 "%s:%d Found duplicate method id (%d) for method: %s\n", 370 filename, item->GetLine(), 371 item->GetId(), item->GetName().c_str()); 372 return 1; 373 } 374 // Ensure that the user set id is within the appropriate limits 375 if (item->GetId() < kMinUserSetMethodId || 376 item->GetId() > kMaxUserSetMethodId) { 377 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n", 378 filename, item->GetLine(), 379 item->GetId(), item->GetName().c_str()); 380 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n", 381 kMinUserSetMethodId, kMaxUserSetMethodId); 382 return 1; 383 } 384 usedIds.insert(item->GetId()); 385 } else { 386 hasUnassignedIds = true; 387 } 388 if (hasAssignedIds && hasUnassignedIds) { 389 fprintf(stderr, 390 "%s: You must either assign id's to all methods or to none of them.\n", 391 filename); 392 return 1; 393 } 394 } 395 396 // In the case that all methods have unassigned id's, set a unique id for them. 397 if (hasUnassignedIds) { 398 int newId = 0; 399 for (const auto& item : items) { 400 item->SetId(newId++); 401 } 402 } 403 404 // success 405 return 0; 406 } 407 408 // TODO: Remove this in favor of using the YACC parser b/25479378 409 bool ParsePreprocessedLine(const string& line, string* decl, 410 vector<string>* package, string* class_name) { 411 // erase all trailing whitespace and semicolons 412 const size_t end = line.find_last_not_of(" ;\t"); 413 if (end == string::npos) { 414 return false; 415 } 416 if (line.rfind(';', end) != string::npos) { 417 return false; 418 } 419 420 decl->clear(); 421 string type; 422 vector<string> pieces = Split(line.substr(0, end + 1), " \t"); 423 for (const string& piece : pieces) { 424 if (piece.empty()) { 425 continue; 426 } 427 if (decl->empty()) { 428 *decl = std::move(piece); 429 } else if (type.empty()) { 430 type = std::move(piece); 431 } else { 432 return false; 433 } 434 } 435 436 // Note that this logic is absolutely wrong. Given a parcelable 437 // org.some.Foo.Bar, the class name is Foo.Bar, but this code will claim that 438 // the class is just Bar. However, this was the way it was done in the past. 439 // 440 // See b/17415692 441 size_t dot_pos = type.rfind('.'); 442 if (dot_pos != string::npos) { 443 *class_name = type.substr(dot_pos + 1); 444 *package = Split(type.substr(0, dot_pos), "."); 445 } else { 446 *class_name = type; 447 package->clear(); 448 } 449 450 return true; 451 } 452 453 } // namespace 454 455 namespace internals { 456 457 bool parse_preprocessed_file(const IoDelegate& io_delegate, 458 const string& filename, TypeNamespace* types) { 459 bool success = true; 460 unique_ptr<LineReader> line_reader = io_delegate.GetLineReader(filename); 461 if (!line_reader) { 462 LOG(ERROR) << "cannot open preprocessed file: " << filename; 463 success = false; 464 return success; 465 } 466 467 string line; 468 unsigned lineno = 1; 469 for ( ; line_reader->ReadLine(&line); ++lineno) { 470 if (line.empty() || line.compare(0, 2, "//") == 0) { 471 // skip comments and empty lines 472 continue; 473 } 474 475 string decl; 476 vector<string> package; 477 string class_name; 478 if (!ParsePreprocessedLine(line, &decl, &package, &class_name)) { 479 success = false; 480 break; 481 } 482 483 if (decl == "parcelable") { 484 AidlParcelable doc(new AidlQualifiedName(class_name, ""), 485 lineno, package); 486 types->AddParcelableType(doc, filename); 487 } else if (decl == "interface") { 488 auto temp = new std::vector<std::unique_ptr<AidlMember>>(); 489 AidlInterface doc(class_name, lineno, "", false, temp, package); 490 types->AddBinderType(doc, filename); 491 } else { 492 success = false; 493 break; 494 } 495 } 496 if (!success) { 497 LOG(ERROR) << filename << ':' << lineno 498 << " malformed preprocessed file line: '" << line << "'"; 499 } 500 501 return success; 502 } 503 504 AidlError load_and_validate_aidl( 505 const std::vector<std::string> preprocessed_files, 506 const std::vector<std::string> import_paths, 507 const std::string& input_file_name, 508 const IoDelegate& io_delegate, 509 TypeNamespace* types, 510 std::unique_ptr<AidlInterface>* returned_interface, 511 std::vector<std::unique_ptr<AidlImport>>* returned_imports) { 512 AidlError err = AidlError::OK; 513 514 std::map<AidlImport*,std::unique_ptr<AidlDocument>> docs; 515 516 // import the preprocessed file 517 for (const string& s : preprocessed_files) { 518 if (!parse_preprocessed_file(io_delegate, s, types)) { 519 err = AidlError::BAD_PRE_PROCESSED_FILE; 520 } 521 } 522 if (err != AidlError::OK) { 523 return err; 524 } 525 526 // parse the input file 527 Parser p{io_delegate}; 528 if (!p.ParseFile(input_file_name)) { 529 return AidlError::PARSE_ERROR; 530 } 531 532 AidlDocument* parsed_doc = p.GetDocument(); 533 534 unique_ptr<AidlInterface> interface(parsed_doc->ReleaseInterface()); 535 536 if (!interface) { 537 LOG(ERROR) << "refusing to generate code from aidl file defining " 538 "parcelable"; 539 return AidlError::FOUND_PARCELABLE; 540 } 541 542 if (!check_filename(input_file_name.c_str(), interface->GetPackage(), 543 interface->GetName(), interface->GetLine()) || 544 !types->IsValidPackage(interface->GetPackage())) { 545 LOG(ERROR) << "Invalid package declaration '" << interface->GetPackage() 546 << "'"; 547 return AidlError::BAD_PACKAGE; 548 } 549 550 // parse the imports of the input file 551 ImportResolver import_resolver{io_delegate, import_paths}; 552 for (auto& import : p.GetImports()) { 553 if (types->HasImportType(*import)) { 554 // There are places in the Android tree where an import doesn't resolve, 555 // but we'll pick the type up through the preprocessed types. 556 // This seems like an error, but legacy support demands we support it... 557 continue; 558 } 559 string import_path = import_resolver.FindImportFile(import->GetNeededClass()); 560 if (import_path.empty()) { 561 cerr << import->GetFileFrom() << ":" << import->GetLine() 562 << ": couldn't find import for class " 563 << import->GetNeededClass() << endl; 564 err = AidlError::BAD_IMPORT; 565 continue; 566 } 567 import->SetFilename(import_path); 568 569 Parser p{io_delegate}; 570 if (!p.ParseFile(import->GetFilename())) { 571 cerr << "error while parsing import for class " 572 << import->GetNeededClass() << endl; 573 err = AidlError::BAD_IMPORT; 574 continue; 575 } 576 577 std::unique_ptr<AidlDocument> document(p.ReleaseDocument()); 578 if (!check_filenames(import->GetFilename(), document.get())) 579 err = AidlError::BAD_IMPORT; 580 docs[import.get()] = std::move(document); 581 } 582 if (err != AidlError::OK) { 583 return err; 584 } 585 586 // gather the types that have been declared 587 if (!types->AddBinderType(*interface.get(), input_file_name)) { 588 err = AidlError::BAD_TYPE; 589 } 590 591 interface->SetLanguageType(types->GetInterfaceType(*interface)); 592 593 for (const auto& import : p.GetImports()) { 594 // If we skipped an unresolved import above (see comment there) we'll have 595 // an empty bucket here. 596 const auto import_itr = docs.find(import.get()); 597 if (import_itr == docs.cend()) { 598 continue; 599 } 600 601 if (!gather_types(import->GetFilename(), import_itr->second.get(), types)) { 602 err = AidlError::BAD_TYPE; 603 } 604 } 605 606 // check the referenced types in parsed_doc to make sure we've imported them 607 if (check_types(input_file_name, interface.get(), types) != 0) { 608 err = AidlError::BAD_TYPE; 609 } 610 if (err != AidlError::OK) { 611 return err; 612 } 613 614 615 // assign method ids and validate. 616 if (check_and_assign_method_ids(input_file_name.c_str(), 617 interface->GetMethods()) != 0) { 618 return AidlError::BAD_METHOD_ID; 619 } 620 621 if (returned_interface) 622 *returned_interface = std::move(interface); 623 624 if (returned_imports) 625 p.ReleaseImports(returned_imports); 626 627 return AidlError::OK; 628 } 629 630 } // namespace internals 631 632 int compile_aidl_to_cpp(const CppOptions& options, 633 const IoDelegate& io_delegate) { 634 unique_ptr<AidlInterface> interface; 635 std::vector<std::unique_ptr<AidlImport>> imports; 636 unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace()); 637 types->Init(); 638 AidlError err = internals::load_and_validate_aidl( 639 std::vector<std::string>{}, // no preprocessed files 640 options.ImportPaths(), 641 options.InputFileName(), 642 io_delegate, 643 types.get(), 644 &interface, 645 &imports); 646 if (err != AidlError::OK) { 647 return 1; 648 } 649 650 if (!write_cpp_dep_file(options, *interface, imports, io_delegate)) { 651 return 1; 652 } 653 654 return (cpp::GenerateCpp(options, *types, *interface, io_delegate)) ? 0 : 1; 655 } 656 657 int compile_aidl_to_java(const JavaOptions& options, 658 const IoDelegate& io_delegate) { 659 unique_ptr<AidlInterface> interface; 660 std::vector<std::unique_ptr<AidlImport>> imports; 661 unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace()); 662 types->Init(); 663 AidlError aidl_err = internals::load_and_validate_aidl( 664 options.preprocessed_files_, 665 options.import_paths_, 666 options.input_file_name_, 667 io_delegate, 668 types.get(), 669 &interface, 670 &imports); 671 if (aidl_err == AidlError::FOUND_PARCELABLE && !options.fail_on_parcelable_) { 672 // We aborted code generation because this file contains parcelables. 673 // However, we were not told to complain if we find parcelables. 674 // Just generate a dep file and exit quietly. The dep file is for a legacy 675 // use case by the SDK. 676 write_java_dep_file(options, imports, io_delegate, ""); 677 return 0; 678 } 679 if (aidl_err != AidlError::OK) { 680 return 1; 681 } 682 683 string output_file_name = options.output_file_name_; 684 // if needed, generate the output file name from the base folder 685 if (output_file_name.empty() && !options.output_base_folder_.empty()) { 686 output_file_name = generate_outputFileName(options, *interface); 687 } 688 689 // make sure the folders of the output file all exists 690 if (!io_delegate.CreatePathForFile(output_file_name)) { 691 return 1; 692 } 693 694 if (!write_java_dep_file(options, imports, io_delegate, output_file_name)) { 695 return 1; 696 } 697 698 return generate_java(output_file_name, options.input_file_name_.c_str(), 699 interface.get(), types.get(), io_delegate); 700 } 701 702 bool preprocess_aidl(const JavaOptions& options, 703 const IoDelegate& io_delegate) { 704 unique_ptr<CodeWriter> writer = 705 io_delegate.GetCodeWriter(options.output_file_name_); 706 707 for (const auto& file : options.files_to_preprocess_) { 708 Parser p{io_delegate}; 709 if (!p.ParseFile(file)) 710 return false; 711 AidlDocument* doc = p.GetDocument(); 712 string line; 713 714 const AidlInterface* interface = doc->GetInterface(); 715 716 if (interface != nullptr && 717 !writer->Write("interface %s;\n", 718 interface->GetCanonicalName().c_str())) { 719 return false; 720 } 721 722 for (const auto& parcelable : doc->GetParcelables()) { 723 if (!writer->Write("parcelable %s;\n", 724 parcelable->GetCanonicalName().c_str())) { 725 return false; 726 } 727 } 728 } 729 730 return writer->Close(); 731 } 732 733 } // namespace android 734 } // namespace aidl 735