1 2 #include "aidl_language.h" 3 #include "options.h" 4 #include "search_path.h" 5 #include "Type.h" 6 #include "generate_java.h" 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <sys/param.h> 10 #include <sys/stat.h> 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <map> 16 17 #ifdef HAVE_MS_C_RUNTIME 18 #include <io.h> 19 #include <direct.h> 20 #include <sys/stat.h> 21 #endif 22 23 #ifndef O_BINARY 24 # define O_BINARY 0 25 #endif 26 27 // The following are gotten as the offset from the allowable id's between 28 // android.os.IBinder.FIRST_CALL_TRANSACTION=1 and 29 // android.os.IBinder.LAST_CALL_TRANSACTION=16777215 30 #define MIN_USER_SET_METHOD_ID 0 31 #define MAX_USER_SET_METHOD_ID 16777214 32 33 using namespace std; 34 35 static void 36 test_document(document_item_type* d) 37 { 38 while (d) { 39 if (d->item_type == INTERFACE_TYPE_BINDER) { 40 interface_type* c = (interface_type*)d; 41 printf("interface %s %s {\n", c->package, c->name.data); 42 interface_item_type *q = (interface_item_type*)c->interface_items; 43 while (q) { 44 if (q->item_type == METHOD_TYPE) { 45 method_type *m = (method_type*)q; 46 printf(" %s %s(", m->type.type.data, m->name.data); 47 arg_type *p = m->args; 48 while (p) { 49 printf("%s %s",p->type.type.data,p->name.data); 50 if (p->next) printf(", "); 51 p=p->next; 52 } 53 printf(")"); 54 printf(";\n"); 55 } 56 q=q->next; 57 } 58 printf("}\n"); 59 } 60 else if (d->item_type == USER_DATA_TYPE) { 61 user_data_type* b = (user_data_type*)d; 62 if ((b->flattening_methods & PARCELABLE_DATA) != 0) { 63 printf("parcelable %s %s;\n", b->package, b->name.data); 64 } 65 if ((b->flattening_methods & RPC_DATA) != 0) { 66 printf("flattenable %s %s;\n", b->package, b->name.data); 67 } 68 } 69 else { 70 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type); 71 } 72 d = d->next; 73 } 74 } 75 76 // ========================================================== 77 int 78 convert_direction(const char* direction) 79 { 80 if (direction == NULL) { 81 return IN_PARAMETER; 82 } 83 if (0 == strcmp(direction, "in")) { 84 return IN_PARAMETER; 85 } 86 if (0 == strcmp(direction, "out")) { 87 return OUT_PARAMETER; 88 } 89 return INOUT_PARAMETER; 90 } 91 92 // ========================================================== 93 struct import_info { 94 const char* from; 95 const char* filename; 96 buffer_type statement; 97 const char* neededClass; 98 document_item_type* doc; 99 struct import_info* next; 100 }; 101 102 document_item_type* g_document = NULL; 103 import_info* g_imports = NULL; 104 105 static void 106 main_document_parsed(document_item_type* d) 107 { 108 g_document = d; 109 } 110 111 static void 112 main_import_parsed(buffer_type* statement) 113 { 114 import_info* import = (import_info*)malloc(sizeof(import_info)); 115 memset(import, 0, sizeof(import_info)); 116 import->from = strdup(g_currentFilename); 117 import->statement.lineno = statement->lineno; 118 import->statement.data = strdup(statement->data); 119 import->statement.extra = NULL; 120 import->next = g_imports; 121 import->neededClass = parse_import_statement(statement->data); 122 g_imports = import; 123 } 124 125 static ParserCallbacks g_mainCallbacks = { 126 &main_document_parsed, 127 &main_import_parsed 128 }; 129 130 char* 131 parse_import_statement(const char* text) 132 { 133 const char* end; 134 int len; 135 136 while (isspace(*text)) { 137 text++; 138 } 139 while (!isspace(*text)) { 140 text++; 141 } 142 while (isspace(*text)) { 143 text++; 144 } 145 end = text; 146 while (!isspace(*end) && *end != ';') { 147 end++; 148 } 149 len = end-text; 150 151 char* rv = (char*)malloc(len+1); 152 memcpy(rv, text, len); 153 rv[len] = '\0'; 154 155 return rv; 156 } 157 158 // ========================================================== 159 static void 160 import_import_parsed(buffer_type* statement) 161 { 162 } 163 164 static ParserCallbacks g_importCallbacks = { 165 &main_document_parsed, 166 &import_import_parsed 167 }; 168 169 // ========================================================== 170 static int 171 check_filename(const char* filename, const char* package, buffer_type* name) 172 { 173 const char* p; 174 string expected; 175 string fn; 176 size_t len; 177 char cwd[MAXPATHLEN]; 178 bool valid = false; 179 180 #ifdef HAVE_WINDOWS_PATHS 181 if (isalpha(filename[0]) && filename[1] == ':' 182 && filename[2] == OS_PATH_SEPARATOR) { 183 #else 184 if (filename[0] == OS_PATH_SEPARATOR) { 185 #endif 186 fn = filename; 187 } else { 188 fn = getcwd(cwd, sizeof(cwd)); 189 len = fn.length(); 190 if (fn[len-1] != OS_PATH_SEPARATOR) { 191 fn += OS_PATH_SEPARATOR; 192 } 193 fn += filename; 194 } 195 196 if (package) { 197 expected = package; 198 expected += '.'; 199 } 200 201 len = expected.length(); 202 for (size_t i=0; i<len; i++) { 203 if (expected[i] == '.') { 204 expected[i] = OS_PATH_SEPARATOR; 205 } 206 } 207 208 p = strchr(name->data, '.'); 209 len = p ? p-name->data : strlen(name->data); 210 expected.append(name->data, len); 211 212 expected += ".aidl"; 213 214 len = fn.length(); 215 valid = (len >= expected.length()); 216 217 if (valid) { 218 p = fn.c_str() + (len - expected.length()); 219 220 #ifdef HAVE_WINDOWS_PATHS 221 if (OS_PATH_SEPARATOR != '/') { 222 // Input filename under cygwin most likely has / separators 223 // whereas the expected string uses \\ separators. Adjust 224 // them accordingly. 225 for (char *c = const_cast<char *>(p); *c; ++c) { 226 if (*c == '/') *c = OS_PATH_SEPARATOR; 227 } 228 } 229 #endif 230 231 // aidl assumes case-insensitivity on Mac Os and Windows. 232 #if defined(__linux__) 233 valid = (expected == p); 234 #else 235 valid = !strcasecmp(expected.c_str(), p); 236 #endif 237 } 238 239 if (!valid) { 240 fprintf(stderr, "%s:%d interface %s should be declared in a file" 241 " called %s.\n", 242 filename, name->lineno, name->data, expected.c_str()); 243 return 1; 244 } 245 246 return 0; 247 } 248 249 static int 250 check_filenames(const char* filename, document_item_type* items) 251 { 252 int err = 0; 253 while (items) { 254 if (items->item_type == USER_DATA_TYPE) { 255 user_data_type* p = (user_data_type*)items; 256 err |= check_filename(filename, p->package, &p->name); 257 } 258 else if (items->item_type == INTERFACE_TYPE_BINDER 259 || items->item_type == INTERFACE_TYPE_RPC) { 260 interface_type* c = (interface_type*)items; 261 err |= check_filename(filename, c->package, &c->name); 262 } 263 else { 264 fprintf(stderr, "aidl: internal error unkown document type %d.\n", 265 items->item_type); 266 return 1; 267 } 268 items = items->next; 269 } 270 return err; 271 } 272 273 // ========================================================== 274 static const char* 275 kind_to_string(int kind) 276 { 277 switch (kind) 278 { 279 case Type::INTERFACE: 280 return "an interface"; 281 case Type::USERDATA: 282 return "a user data"; 283 default: 284 return "ERROR"; 285 } 286 } 287 288 static char* 289 rfind(char* str, char c) 290 { 291 char* p = str + strlen(str) - 1; 292 while (p >= str) { 293 if (*p == c) { 294 return p; 295 } 296 p--; 297 } 298 return NULL; 299 } 300 301 static int 302 gather_types(const char* filename, document_item_type* items) 303 { 304 int err = 0; 305 while (items) { 306 Type* type; 307 if (items->item_type == USER_DATA_TYPE) { 308 user_data_type* p = (user_data_type*)items; 309 type = new UserDataType(p->package ? p->package : "", p->name.data, 310 false, ((p->flattening_methods & PARCELABLE_DATA) != 0), 311 ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno); 312 } 313 else if (items->item_type == INTERFACE_TYPE_BINDER 314 || items->item_type == INTERFACE_TYPE_RPC) { 315 interface_type* c = (interface_type*)items; 316 type = new InterfaceType(c->package ? c->package : "", 317 c->name.data, false, c->oneway, 318 filename, c->name.lineno); 319 } 320 else { 321 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__); 322 return 1; 323 } 324 325 Type* old = NAMES.Find(type->QualifiedName()); 326 if (old == NULL) { 327 NAMES.Add(type); 328 329 if (items->item_type == INTERFACE_TYPE_BINDER) { 330 // for interfaces, also add the stub and proxy types, we don't 331 // bother checking these for duplicates, because the parser 332 // won't let us do it. 333 interface_type* c = (interface_type*)items; 334 335 string name = c->name.data; 336 name += ".Stub"; 337 Type* stub = new Type(c->package ? c->package : "", 338 name, Type::GENERATED, false, false, false, 339 filename, c->name.lineno); 340 NAMES.Add(stub); 341 342 name = c->name.data; 343 name += ".Stub.Proxy"; 344 Type* proxy = new Type(c->package ? c->package : "", 345 name, Type::GENERATED, false, false, false, 346 filename, c->name.lineno); 347 NAMES.Add(proxy); 348 } 349 else if (items->item_type == INTERFACE_TYPE_RPC) { 350 // for interfaces, also add the service base type, we don't 351 // bother checking these for duplicates, because the parser 352 // won't let us do it. 353 interface_type* c = (interface_type*)items; 354 355 string name = c->name.data; 356 name += ".ServiceBase"; 357 Type* base = new Type(c->package ? c->package : "", 358 name, Type::GENERATED, false, false, false, 359 filename, c->name.lineno); 360 NAMES.Add(base); 361 } 362 } else { 363 if (old->Kind() == Type::BUILT_IN) { 364 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n", 365 filename, type->DeclLine(), 366 type->QualifiedName().c_str()); 367 err = 1; 368 } 369 else if (type->Kind() != old->Kind()) { 370 const char* oldKind = kind_to_string(old->Kind()); 371 const char* newKind = kind_to_string(type->Kind()); 372 373 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n", 374 filename, type->DeclLine(), 375 type->QualifiedName().c_str(), newKind); 376 fprintf(stderr, "%s:%d previously defined here as %s.\n", 377 old->DeclFile().c_str(), old->DeclLine(), oldKind); 378 err = 1; 379 } 380 } 381 382 items = items->next; 383 } 384 return err; 385 } 386 387 // ========================================================== 388 static bool 389 matches_keyword(const char* str) 390 { 391 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break", 392 "byte", "case", "catch", "char", "class", "const", "continue", 393 "default", "do", "double", "else", "enum", "extends", "final", 394 "finally", "float", "for", "goto", "if", "implements", "import", 395 "instanceof", "int", "interface", "long", "native", "new", "package", 396 "private", "protected", "public", "return", "short", "static", 397 "strictfp", "super", "switch", "synchronized", "this", "throw", 398 "throws", "transient", "try", "void", "volatile", "while", 399 "true", "false", "null", 400 NULL 401 }; 402 const char** k = KEYWORDS; 403 while (*k) { 404 if (0 == strcmp(str, *k)) { 405 return true; 406 } 407 k++; 408 } 409 return false; 410 } 411 412 static int 413 check_method(const char* filename, int kind, method_type* m) 414 { 415 int err = 0; 416 417 // return type 418 Type* returnType = NAMES.Search(m->type.type.data); 419 if (returnType == NULL) { 420 fprintf(stderr, "%s:%d unknown return type %s\n", filename, 421 m->type.type.lineno, m->type.type.data); 422 err = 1; 423 return err; 424 } 425 426 if (returnType == EVENT_FAKE_TYPE) { 427 if (kind != INTERFACE_TYPE_RPC) { 428 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n", 429 filename, m->type.type.lineno); 430 err = 1; 431 } 432 } else { 433 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel() 434 : returnType->CanWriteToRpcData())) { 435 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename, 436 m->type.type.lineno, m->type.type.data); 437 err = 1; 438 } 439 } 440 441 if (m->type.dimension > 0 && !returnType->CanBeArray()) { 442 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename, 443 m->type.array_token.lineno, m->type.type.data, 444 m->type.array_token.data); 445 err = 1; 446 } 447 448 if (m->type.dimension > 1) { 449 fprintf(stderr, "%s:%d return type %s%s only one" 450 " dimensional arrays are supported\n", filename, 451 m->type.array_token.lineno, m->type.type.data, 452 m->type.array_token.data); 453 err = 1; 454 } 455 456 int index = 1; 457 458 arg_type* arg = m->args; 459 while (arg) { 460 Type* t = NAMES.Search(arg->type.type.data); 461 462 // check the arg type 463 if (t == NULL) { 464 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n", 465 filename, m->type.type.lineno, arg->name.data, index, 466 arg->type.type.data); 467 err = 1; 468 goto next; 469 } 470 471 if (t == EVENT_FAKE_TYPE) { 472 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n", 473 filename, m->type.type.lineno, arg->name.data, index, 474 arg->type.type.data); 475 err = 1; 476 goto next; 477 } 478 479 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) { 480 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n", 481 filename, m->type.type.lineno, index, 482 arg->type.type.data, arg->name.data); 483 err = 1; 484 } 485 486 if (returnType == EVENT_FAKE_TYPE 487 && convert_direction(arg->direction.data) != IN_PARAMETER) { 488 fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n", 489 filename, m->type.type.lineno, index, 490 arg->type.type.data, arg->name.data); 491 err = 1; 492 goto next; 493 } 494 495 if (arg->direction.data == NULL 496 && (arg->type.dimension != 0 || t->CanBeOutParameter())) { 497 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out" 498 " parameter, so you must declare it as in," 499 " out or inout.\n", 500 filename, m->type.type.lineno, index, 501 arg->type.type.data, arg->name.data); 502 err = 1; 503 } 504 505 if (convert_direction(arg->direction.data) != IN_PARAMETER 506 && !t->CanBeOutParameter() 507 && arg->type.dimension == 0) { 508 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in" 509 " parameter.\n", 510 filename, m->type.type.lineno, index, 511 arg->direction.data, arg->type.type.data, 512 arg->name.data); 513 err = 1; 514 } 515 516 if (arg->type.dimension > 0 && !t->CanBeArray()) { 517 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an" 518 " array.\n", filename, 519 m->type.array_token.lineno, index, arg->direction.data, 520 arg->type.type.data, arg->type.array_token.data, 521 arg->name.data); 522 err = 1; 523 } 524 525 if (arg->type.dimension > 1) { 526 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one" 527 " dimensional arrays are supported\n", filename, 528 m->type.array_token.lineno, index, arg->direction.data, 529 arg->type.type.data, arg->type.array_token.data, 530 arg->name.data); 531 err = 1; 532 } 533 534 // check that the name doesn't match a keyword 535 if (matches_keyword(arg->name.data)) { 536 fprintf(stderr, "%s:%d parameter %d %s is named the same as a" 537 " Java or aidl keyword\n", 538 filename, m->name.lineno, index, arg->name.data); 539 err = 1; 540 } 541 542 next: 543 index++; 544 arg = arg->next; 545 } 546 547 return err; 548 } 549 550 static int 551 check_types(const char* filename, document_item_type* items) 552 { 553 int err = 0; 554 while (items) { 555 // (nothing to check for USER_DATA_TYPE) 556 if (items->item_type == INTERFACE_TYPE_BINDER 557 || items->item_type == INTERFACE_TYPE_RPC) { 558 map<string,method_type*> methodNames; 559 interface_type* c = (interface_type*)items; 560 561 interface_item_type* member = c->interface_items; 562 while (member) { 563 if (member->item_type == METHOD_TYPE) { 564 method_type* m = (method_type*)member; 565 566 err |= check_method(filename, items->item_type, m); 567 568 // prevent duplicate methods 569 if (methodNames.find(m->name.data) == methodNames.end()) { 570 methodNames[m->name.data] = m; 571 } else { 572 fprintf(stderr,"%s:%d attempt to redefine method %s,\n", 573 filename, m->name.lineno, m->name.data); 574 method_type* old = methodNames[m->name.data]; 575 fprintf(stderr, "%s:%d previously defined here.\n", 576 filename, old->name.lineno); 577 err = 1; 578 } 579 } 580 member = member->next; 581 } 582 } 583 584 items = items->next; 585 } 586 return err; 587 } 588 589 // ========================================================== 590 static int 591 exactly_one_interface(const char* filename, const document_item_type* items, const Options& options, 592 bool* onlyParcelable) 593 { 594 if (items == NULL) { 595 fprintf(stderr, "%s: file does not contain any interfaces\n", 596 filename); 597 return 1; 598 } 599 600 const document_item_type* next = items->next; 601 // Allow parcelables to skip the "one-only" rule. 602 if (items->next != NULL && next->item_type != USER_DATA_TYPE) { 603 int lineno = -1; 604 if (next->item_type == INTERFACE_TYPE_BINDER) { 605 lineno = ((interface_type*)next)->interface_token.lineno; 606 } 607 else if (next->item_type == INTERFACE_TYPE_RPC) { 608 lineno = ((interface_type*)next)->interface_token.lineno; 609 } 610 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n", 611 filename, lineno); 612 return 1; 613 } 614 615 if (items->item_type == USER_DATA_TYPE) { 616 *onlyParcelable = true; 617 if (options.failOnParcelable) { 618 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not" 619 " parcelables or flattenables,\n", filename, 620 ((user_data_type*)items)->keyword_token.lineno); 621 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables" 622 "may not go in the Makefile.\n", filename, 623 ((user_data_type*)items)->keyword_token.lineno); 624 return 1; 625 } 626 } else { 627 *onlyParcelable = false; 628 } 629 630 return 0; 631 } 632 633 // ========================================================== 634 void 635 generate_dep_file(const Options& options, const document_item_type* items) 636 { 637 /* we open the file in binary mode to ensure that the same output is 638 * generated on all platforms !! 639 */ 640 FILE* to = NULL; 641 if (options.autoDepFile) { 642 string fileName = options.outputFileName + ".d"; 643 to = fopen(fileName.c_str(), "wb"); 644 } else { 645 to = fopen(options.depFileName.c_str(), "wb"); 646 } 647 648 if (to == NULL) { 649 return; 650 } 651 652 const char* slash = "\\"; 653 import_info* import = g_imports; 654 if (import == NULL) { 655 slash = ""; 656 } 657 658 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) { 659 fprintf(to, "%s: \\\n", options.outputFileName.c_str()); 660 } else { 661 // parcelable: there's no output file. 662 fprintf(to, " : \\\n"); 663 } 664 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash); 665 666 while (import) { 667 if (import->next == NULL) { 668 slash = ""; 669 } 670 if (import->filename) { 671 fprintf(to, " %s %s\n", import->filename, slash); 672 } 673 import = import->next; 674 } 675 676 fprintf(to, "\n"); 677 678 // Output "<imported_file>: " so make won't fail if the imported file has 679 // been deleted, moved or renamed in incremental build. 680 import = g_imports; 681 while (import) { 682 if (import->filename) { 683 fprintf(to, "%s :\n", import->filename); 684 } 685 import = import->next; 686 } 687 688 fclose(to); 689 } 690 691 // ========================================================== 692 static string 693 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package) 694 { 695 string result; 696 697 // create the path to the destination folder based on the 698 // interface package name 699 result = options.outputBaseFolder; 700 result += OS_PATH_SEPARATOR; 701 702 string packageStr = package; 703 size_t len = packageStr.length(); 704 for (size_t i=0; i<len; i++) { 705 if (packageStr[i] == '.') { 706 packageStr[i] = OS_PATH_SEPARATOR; 707 } 708 } 709 710 result += packageStr; 711 712 // add the filename by replacing the .aidl extension to .java 713 const char* p = strchr(name.data, '.'); 714 len = p ? p-name.data : strlen(name.data); 715 716 result += OS_PATH_SEPARATOR; 717 result.append(name.data, len); 718 result += ".java"; 719 720 return result; 721 } 722 723 // ========================================================== 724 static string 725 generate_outputFileName(const Options& options, const document_item_type* items) 726 { 727 // items has already been checked to have only one interface. 728 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) { 729 interface_type* type = (interface_type*)items; 730 731 return generate_outputFileName2(options, type->name, type->package); 732 } else if (items->item_type == USER_DATA_TYPE) { 733 user_data_type* type = (user_data_type*)items; 734 return generate_outputFileName2(options, type->name, type->package); 735 } 736 737 // I don't think we can come here, but safer than returning NULL. 738 string result; 739 return result; 740 } 741 742 743 744 // ========================================================== 745 static void 746 check_outputFilePath(const string& path) { 747 size_t len = path.length(); 748 for (size_t i=0; i<len ; i++) { 749 if (path[i] == OS_PATH_SEPARATOR) { 750 string p = path.substr(0, i); 751 if (access(path.data(), F_OK) != 0) { 752 #ifdef HAVE_MS_C_RUNTIME 753 _mkdir(p.data()); 754 #else 755 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP); 756 #endif 757 } 758 } 759 } 760 } 761 762 763 // ========================================================== 764 static int 765 parse_preprocessed_file(const string& filename) 766 { 767 int err; 768 769 FILE* f = fopen(filename.c_str(), "rb"); 770 if (f == NULL) { 771 fprintf(stderr, "aidl: can't open preprocessed file: %s\n", 772 filename.c_str()); 773 return 1; 774 } 775 776 int lineno = 1; 777 char line[1024]; 778 char type[1024]; 779 char fullname[1024]; 780 while (fgets(line, sizeof(line), f)) { 781 // skip comments and empty lines 782 if (!line[0] || strncmp(line, "//", 2) == 0) { 783 continue; 784 } 785 786 sscanf(line, "%s %[^; \r\n\t];", type, fullname); 787 788 char* packagename; 789 char* classname = rfind(fullname, '.'); 790 if (classname != NULL) { 791 *classname = '\0'; 792 classname++; 793 packagename = fullname; 794 } else { 795 classname = fullname; 796 packagename = NULL; 797 } 798 799 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno, 800 // type, packagename, classname); 801 document_item_type* doc; 802 803 if (0 == strcmp("parcelable", type)) { 804 user_data_type* parcl = (user_data_type*)malloc( 805 sizeof(user_data_type)); 806 memset(parcl, 0, sizeof(user_data_type)); 807 parcl->document_item.item_type = USER_DATA_TYPE; 808 parcl->keyword_token.lineno = lineno; 809 parcl->keyword_token.data = strdup(type); 810 parcl->package = packagename ? strdup(packagename) : NULL; 811 parcl->name.lineno = lineno; 812 parcl->name.data = strdup(classname); 813 parcl->semicolon_token.lineno = lineno; 814 parcl->semicolon_token.data = strdup(";"); 815 parcl->flattening_methods = PARCELABLE_DATA; 816 doc = (document_item_type*)parcl; 817 } 818 else if (0 == strcmp("flattenable", type)) { 819 user_data_type* parcl = (user_data_type*)malloc( 820 sizeof(user_data_type)); 821 memset(parcl, 0, sizeof(user_data_type)); 822 parcl->document_item.item_type = USER_DATA_TYPE; 823 parcl->keyword_token.lineno = lineno; 824 parcl->keyword_token.data = strdup(type); 825 parcl->package = packagename ? strdup(packagename) : NULL; 826 parcl->name.lineno = lineno; 827 parcl->name.data = strdup(classname); 828 parcl->semicolon_token.lineno = lineno; 829 parcl->semicolon_token.data = strdup(";"); 830 parcl->flattening_methods = RPC_DATA; 831 doc = (document_item_type*)parcl; 832 } 833 else if (0 == strcmp("interface", type)) { 834 interface_type* iface = (interface_type*)malloc( 835 sizeof(interface_type)); 836 memset(iface, 0, sizeof(interface_type)); 837 iface->document_item.item_type = INTERFACE_TYPE_BINDER; 838 iface->interface_token.lineno = lineno; 839 iface->interface_token.data = strdup(type); 840 iface->package = packagename ? strdup(packagename) : NULL; 841 iface->name.lineno = lineno; 842 iface->name.data = strdup(classname); 843 iface->open_brace_token.lineno = lineno; 844 iface->open_brace_token.data = strdup("{"); 845 iface->close_brace_token.lineno = lineno; 846 iface->close_brace_token.data = strdup("}"); 847 doc = (document_item_type*)iface; 848 } 849 else { 850 fprintf(stderr, "%s:%d: bad type in line: %s\n", 851 filename.c_str(), lineno, line); 852 fclose(f); 853 return 1; 854 } 855 err = gather_types(filename.c_str(), doc); 856 lineno++; 857 } 858 859 if (!feof(f)) { 860 fprintf(stderr, "%s:%d: error reading file, line to long.\n", 861 filename.c_str(), lineno); 862 return 1; 863 } 864 865 fclose(f); 866 return 0; 867 } 868 869 static int 870 check_and_assign_method_ids(const char * filename, interface_item_type* first_item) 871 { 872 // Check whether there are any methods with manually assigned id's and any that are not. 873 // Either all method id's must be manually assigned or all of them must not. 874 // Also, check for duplicates of user set id's and that the id's are within the proper bounds. 875 set<int> usedIds; 876 interface_item_type* item = first_item; 877 bool hasUnassignedIds = false; 878 bool hasAssignedIds = false; 879 while (item != NULL) { 880 if (item->item_type == METHOD_TYPE) { 881 method_type* method_item = (method_type*)item; 882 if (method_item->hasId) { 883 hasAssignedIds = true; 884 method_item->assigned_id = atoi(method_item->id.data); 885 // Ensure that the user set id is not duplicated. 886 if (usedIds.find(method_item->assigned_id) != usedIds.end()) { 887 // We found a duplicate id, so throw an error. 888 fprintf(stderr, 889 "%s:%d Found duplicate method id (%d) for method: %s\n", 890 filename, method_item->id.lineno, 891 method_item->assigned_id, method_item->name.data); 892 return 1; 893 } 894 // Ensure that the user set id is within the appropriate limits 895 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID || 896 method_item->assigned_id > MAX_USER_SET_METHOD_ID) { 897 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n", 898 filename, method_item->id.lineno, 899 method_item->assigned_id, method_item->name.data); 900 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n", 901 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID); 902 return 1; 903 } 904 usedIds.insert(method_item->assigned_id); 905 } else { 906 hasUnassignedIds = true; 907 } 908 if (hasAssignedIds && hasUnassignedIds) { 909 fprintf(stderr, 910 "%s: You must either assign id's to all methods or to none of them.\n", 911 filename); 912 return 1; 913 } 914 } 915 item = item->next; 916 } 917 918 // In the case that all methods have unassigned id's, set a unique id for them. 919 if (hasUnassignedIds) { 920 int newId = 0; 921 item = first_item; 922 while (item != NULL) { 923 if (item->item_type == METHOD_TYPE) { 924 method_type* method_item = (method_type*)item; 925 method_item->assigned_id = newId++; 926 } 927 item = item->next; 928 } 929 } 930 931 // success 932 return 0; 933 } 934 935 // ========================================================== 936 static int 937 compile_aidl(Options& options) 938 { 939 int err = 0, N; 940 941 set_import_paths(options.importPaths); 942 943 register_base_types(); 944 945 // import the preprocessed file 946 N = options.preprocessedFiles.size(); 947 for (int i=0; i<N; i++) { 948 const string& s = options.preprocessedFiles[i]; 949 err |= parse_preprocessed_file(s); 950 } 951 if (err != 0) { 952 return err; 953 } 954 955 // parse the main file 956 g_callbacks = &g_mainCallbacks; 957 err = parse_aidl(options.inputFileName.c_str()); 958 document_item_type* mainDoc = g_document; 959 g_document = NULL; 960 961 // parse the imports 962 g_callbacks = &g_mainCallbacks; 963 import_info* import = g_imports; 964 while (import) { 965 if (NAMES.Find(import->neededClass) == NULL) { 966 import->filename = find_import_file(import->neededClass); 967 if (!import->filename) { 968 fprintf(stderr, "%s:%d: couldn't find import for class %s\n", 969 import->from, import->statement.lineno, 970 import->neededClass); 971 err |= 1; 972 } else { 973 err |= parse_aidl(import->filename); 974 import->doc = g_document; 975 if (import->doc == NULL) { 976 err |= 1; 977 } 978 } 979 } 980 import = import->next; 981 } 982 // bail out now if parsing wasn't successful 983 if (err != 0 || mainDoc == NULL) { 984 //fprintf(stderr, "aidl: parsing failed, stopping.\n"); 985 return 1; 986 } 987 988 // complain about ones that aren't in the right files 989 err |= check_filenames(options.inputFileName.c_str(), mainDoc); 990 import = g_imports; 991 while (import) { 992 err |= check_filenames(import->filename, import->doc); 993 import = import->next; 994 } 995 996 // gather the types that have been declared 997 err |= gather_types(options.inputFileName.c_str(), mainDoc); 998 import = g_imports; 999 while (import) { 1000 err |= gather_types(import->filename, import->doc); 1001 import = import->next; 1002 } 1003 1004 #if 0 1005 printf("---- main doc ----\n"); 1006 test_document(mainDoc); 1007 1008 import = g_imports; 1009 while (import) { 1010 printf("---- import doc ----\n"); 1011 test_document(import->doc); 1012 import = import->next; 1013 } 1014 NAMES.Dump(); 1015 #endif 1016 1017 // check the referenced types in mainDoc to make sure we've imported them 1018 err |= check_types(options.inputFileName.c_str(), mainDoc); 1019 1020 // finally, there really only needs to be one thing in mainDoc, and it 1021 // needs to be an interface. 1022 bool onlyParcelable = false; 1023 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable); 1024 1025 // If this includes an interface definition, then assign method ids and validate. 1026 if (!onlyParcelable) { 1027 err |= check_and_assign_method_ids(options.inputFileName.c_str(), 1028 ((interface_type*)mainDoc)->interface_items); 1029 } 1030 1031 // after this, there shouldn't be any more errors because of the 1032 // input. 1033 if (err != 0 || mainDoc == NULL) { 1034 return 1; 1035 } 1036 1037 // if needed, generate the outputFileName from the outputBaseFolder 1038 if (options.outputFileName.length() == 0 && 1039 options.outputBaseFolder.length() > 0) { 1040 options.outputFileName = generate_outputFileName(options, mainDoc); 1041 } 1042 1043 // if we were asked to, generate a make dependency file 1044 // unless it's a parcelable *and* it's supposed to fail on parcelable 1045 if ((options.autoDepFile || options.depFileName != "") && 1046 !(onlyParcelable && options.failOnParcelable)) { 1047 // make sure the folders of the output file all exists 1048 check_outputFilePath(options.outputFileName); 1049 generate_dep_file(options, mainDoc); 1050 } 1051 1052 // they didn't ask to fail on parcelables, so just exit quietly. 1053 if (onlyParcelable && !options.failOnParcelable) { 1054 return 0; 1055 } 1056 1057 // make sure the folders of the output file all exists 1058 check_outputFilePath(options.outputFileName); 1059 1060 err = generate_java(options.outputFileName, options.inputFileName.c_str(), 1061 (interface_type*)mainDoc); 1062 1063 return err; 1064 } 1065 1066 static int 1067 preprocess_aidl(const Options& options) 1068 { 1069 vector<string> lines; 1070 int err; 1071 1072 // read files 1073 int N = options.filesToPreprocess.size(); 1074 for (int i=0; i<N; i++) { 1075 g_callbacks = &g_mainCallbacks; 1076 err = parse_aidl(options.filesToPreprocess[i].c_str()); 1077 if (err != 0) { 1078 return err; 1079 } 1080 document_item_type* doc = g_document; 1081 string line; 1082 if (doc->item_type == USER_DATA_TYPE) { 1083 user_data_type* parcelable = (user_data_type*)doc; 1084 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) { 1085 line = "parcelable "; 1086 } 1087 if ((parcelable->flattening_methods & RPC_DATA) != 0) { 1088 line = "flattenable "; 1089 } 1090 if (parcelable->package) { 1091 line += parcelable->package; 1092 line += '.'; 1093 } 1094 line += parcelable->name.data; 1095 } else { 1096 line = "interface "; 1097 interface_type* iface = (interface_type*)doc; 1098 if (iface->package) { 1099 line += iface->package; 1100 line += '.'; 1101 } 1102 line += iface->name.data; 1103 } 1104 line += ";\n"; 1105 lines.push_back(line); 1106 } 1107 1108 // write preprocessed file 1109 int fd = open( options.outputFileName.c_str(), 1110 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 1111 #ifdef HAVE_MS_C_RUNTIME 1112 _S_IREAD|_S_IWRITE); 1113 #else 1114 S_IRUSR|S_IWUSR|S_IRGRP); 1115 #endif 1116 if (fd == -1) { 1117 fprintf(stderr, "aidl: could not open file for write: %s\n", 1118 options.outputFileName.c_str()); 1119 return 1; 1120 } 1121 1122 N = lines.size(); 1123 for (int i=0; i<N; i++) { 1124 const string& s = lines[i]; 1125 int len = s.length(); 1126 if (len != write(fd, s.c_str(), len)) { 1127 fprintf(stderr, "aidl: error writing to file %s\n", 1128 options.outputFileName.c_str()); 1129 close(fd); 1130 unlink(options.outputFileName.c_str()); 1131 return 1; 1132 } 1133 } 1134 1135 close(fd); 1136 return 0; 1137 } 1138 1139 // ========================================================== 1140 int 1141 main(int argc, const char **argv) 1142 { 1143 Options options; 1144 int result = parse_options(argc, argv, &options); 1145 if (result) { 1146 return result; 1147 } 1148 1149 switch (options.task) 1150 { 1151 case COMPILE_AIDL: 1152 return compile_aidl(options); 1153 case PREPROCESS_AIDL: 1154 return preprocess_aidl(options); 1155 } 1156 fprintf(stderr, "aidl: internal error\n"); 1157 return 1; 1158 } 1159