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