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