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 fclose(to); 677 } 678 679 // ========================================================== 680 static string 681 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package) 682 { 683 string result; 684 685 // create the path to the destination folder based on the 686 // interface package name 687 result = options.outputBaseFolder; 688 result += OS_PATH_SEPARATOR; 689 690 string packageStr = package; 691 size_t len = packageStr.length(); 692 for (size_t i=0; i<len; i++) { 693 if (packageStr[i] == '.') { 694 packageStr[i] = OS_PATH_SEPARATOR; 695 } 696 } 697 698 result += packageStr; 699 700 // add the filename by replacing the .aidl extension to .java 701 const char* p = strchr(name.data, '.'); 702 len = p ? p-name.data : strlen(name.data); 703 704 result += OS_PATH_SEPARATOR; 705 result.append(name.data, len); 706 result += ".java"; 707 708 return result; 709 } 710 711 // ========================================================== 712 static string 713 generate_outputFileName(const Options& options, const document_item_type* items) 714 { 715 // items has already been checked to have only one interface. 716 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) { 717 interface_type* type = (interface_type*)items; 718 719 return generate_outputFileName2(options, type->name, type->package); 720 } else if (items->item_type == USER_DATA_TYPE) { 721 user_data_type* type = (user_data_type*)items; 722 return generate_outputFileName2(options, type->name, type->package); 723 } 724 725 // I don't think we can come here, but safer than returning NULL. 726 string result; 727 return result; 728 } 729 730 731 732 // ========================================================== 733 static void 734 check_outputFilePath(const string& path) { 735 size_t len = path.length(); 736 for (size_t i=0; i<len ; i++) { 737 if (path[i] == OS_PATH_SEPARATOR) { 738 string p = path.substr(0, i); 739 if (access(path.data(), F_OK) != 0) { 740 #ifdef HAVE_MS_C_RUNTIME 741 _mkdir(p.data()); 742 #else 743 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP); 744 #endif 745 } 746 } 747 } 748 } 749 750 751 // ========================================================== 752 static int 753 parse_preprocessed_file(const string& filename) 754 { 755 int err; 756 757 FILE* f = fopen(filename.c_str(), "rb"); 758 if (f == NULL) { 759 fprintf(stderr, "aidl: can't open preprocessed file: %s\n", 760 filename.c_str()); 761 return 1; 762 } 763 764 int lineno = 1; 765 char line[1024]; 766 char type[1024]; 767 char fullname[1024]; 768 while (fgets(line, sizeof(line), f)) { 769 // skip comments and empty lines 770 if (!line[0] || strncmp(line, "//", 2) == 0) { 771 continue; 772 } 773 774 sscanf(line, "%s %[^; \r\n\t];", type, fullname); 775 776 char* packagename; 777 char* classname = rfind(fullname, '.'); 778 if (classname != NULL) { 779 *classname = '\0'; 780 classname++; 781 packagename = fullname; 782 } else { 783 classname = fullname; 784 packagename = NULL; 785 } 786 787 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno, 788 // type, packagename, classname); 789 document_item_type* doc; 790 791 if (0 == strcmp("parcelable", type)) { 792 user_data_type* parcl = (user_data_type*)malloc( 793 sizeof(user_data_type)); 794 memset(parcl, 0, sizeof(user_data_type)); 795 parcl->document_item.item_type = USER_DATA_TYPE; 796 parcl->keyword_token.lineno = lineno; 797 parcl->keyword_token.data = strdup(type); 798 parcl->package = packagename ? strdup(packagename) : NULL; 799 parcl->name.lineno = lineno; 800 parcl->name.data = strdup(classname); 801 parcl->semicolon_token.lineno = lineno; 802 parcl->semicolon_token.data = strdup(";"); 803 parcl->flattening_methods = PARCELABLE_DATA; 804 doc = (document_item_type*)parcl; 805 } 806 else if (0 == strcmp("flattenable", type)) { 807 user_data_type* parcl = (user_data_type*)malloc( 808 sizeof(user_data_type)); 809 memset(parcl, 0, sizeof(user_data_type)); 810 parcl->document_item.item_type = USER_DATA_TYPE; 811 parcl->keyword_token.lineno = lineno; 812 parcl->keyword_token.data = strdup(type); 813 parcl->package = packagename ? strdup(packagename) : NULL; 814 parcl->name.lineno = lineno; 815 parcl->name.data = strdup(classname); 816 parcl->semicolon_token.lineno = lineno; 817 parcl->semicolon_token.data = strdup(";"); 818 parcl->flattening_methods = RPC_DATA; 819 doc = (document_item_type*)parcl; 820 } 821 else if (0 == strcmp("interface", type)) { 822 interface_type* iface = (interface_type*)malloc( 823 sizeof(interface_type)); 824 memset(iface, 0, sizeof(interface_type)); 825 iface->document_item.item_type = INTERFACE_TYPE_BINDER; 826 iface->interface_token.lineno = lineno; 827 iface->interface_token.data = strdup(type); 828 iface->package = packagename ? strdup(packagename) : NULL; 829 iface->name.lineno = lineno; 830 iface->name.data = strdup(classname); 831 iface->open_brace_token.lineno = lineno; 832 iface->open_brace_token.data = strdup("{"); 833 iface->close_brace_token.lineno = lineno; 834 iface->close_brace_token.data = strdup("}"); 835 doc = (document_item_type*)iface; 836 } 837 else { 838 fprintf(stderr, "%s:%d: bad type in line: %s\n", 839 filename.c_str(), lineno, line); 840 return 1; 841 } 842 err = gather_types(filename.c_str(), doc); 843 lineno++; 844 } 845 846 if (!feof(f)) { 847 fprintf(stderr, "%s:%d: error reading file, line to long.\n", 848 filename.c_str(), lineno); 849 return 1; 850 } 851 852 fclose(f); 853 return 0; 854 } 855 856 static int 857 check_and_assign_method_ids(const char * filename, interface_item_type* first_item) 858 { 859 // Check whether there are any methods with manually assigned id's and any that are not. 860 // Either all method id's must be manually assigned or all of them must not. 861 // Also, check for duplicates of user set id's and that the id's are within the proper bounds. 862 set<int> usedIds; 863 interface_item_type* item = first_item; 864 bool hasUnassignedIds = false; 865 bool hasAssignedIds = false; 866 while (item != NULL) { 867 if (item->item_type == METHOD_TYPE) { 868 method_type* method_item = (method_type*)item; 869 if (method_item->hasId) { 870 hasAssignedIds = true; 871 method_item->assigned_id = atoi(method_item->id.data); 872 // Ensure that the user set id is not duplicated. 873 if (usedIds.find(method_item->assigned_id) != usedIds.end()) { 874 // We found a duplicate id, so throw an error. 875 fprintf(stderr, 876 "%s:%d Found duplicate method id (%d) for method: %s\n", 877 filename, method_item->id.lineno, 878 method_item->assigned_id, method_item->name.data); 879 return 1; 880 } 881 // Ensure that the user set id is within the appropriate limits 882 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID || 883 method_item->assigned_id > MAX_USER_SET_METHOD_ID) { 884 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n", 885 filename, method_item->id.lineno, 886 method_item->assigned_id, method_item->name.data); 887 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n", 888 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID); 889 return 1; 890 } 891 usedIds.insert(method_item->assigned_id); 892 } else { 893 hasUnassignedIds = true; 894 } 895 if (hasAssignedIds && hasUnassignedIds) { 896 fprintf(stderr, 897 "%s: You must either assign id's to all methods or to none of them.\n", 898 filename); 899 return 1; 900 } 901 } 902 item = item->next; 903 } 904 905 // In the case that all methods have unassigned id's, set a unique id for them. 906 if (hasUnassignedIds) { 907 int newId = 0; 908 item = first_item; 909 while (item != NULL) { 910 if (item->item_type == METHOD_TYPE) { 911 method_type* method_item = (method_type*)item; 912 method_item->assigned_id = newId++; 913 } 914 item = item->next; 915 } 916 } 917 918 // success 919 return 0; 920 } 921 922 // ========================================================== 923 static int 924 compile_aidl(Options& options) 925 { 926 int err = 0, N; 927 928 set_import_paths(options.importPaths); 929 930 register_base_types(); 931 932 // import the preprocessed file 933 N = options.preprocessedFiles.size(); 934 for (int i=0; i<N; i++) { 935 const string& s = options.preprocessedFiles[i]; 936 err |= parse_preprocessed_file(s); 937 } 938 if (err != 0) { 939 return err; 940 } 941 942 // parse the main file 943 g_callbacks = &g_mainCallbacks; 944 err = parse_aidl(options.inputFileName.c_str()); 945 document_item_type* mainDoc = g_document; 946 g_document = NULL; 947 948 // parse the imports 949 g_callbacks = &g_mainCallbacks; 950 import_info* import = g_imports; 951 while (import) { 952 if (NAMES.Find(import->neededClass) == NULL) { 953 import->filename = find_import_file(import->neededClass); 954 if (!import->filename) { 955 fprintf(stderr, "%s:%d: couldn't find import for class %s\n", 956 import->from, import->statement.lineno, 957 import->neededClass); 958 err |= 1; 959 } else { 960 err |= parse_aidl(import->filename); 961 import->doc = g_document; 962 if (import->doc == NULL) { 963 err |= 1; 964 } 965 } 966 } 967 import = import->next; 968 } 969 // bail out now if parsing wasn't successful 970 if (err != 0 || mainDoc == NULL) { 971 //fprintf(stderr, "aidl: parsing failed, stopping.\n"); 972 return 1; 973 } 974 975 // complain about ones that aren't in the right files 976 err |= check_filenames(options.inputFileName.c_str(), mainDoc); 977 import = g_imports; 978 while (import) { 979 err |= check_filenames(import->filename, import->doc); 980 import = import->next; 981 } 982 983 // gather the types that have been declared 984 err |= gather_types(options.inputFileName.c_str(), mainDoc); 985 import = g_imports; 986 while (import) { 987 err |= gather_types(import->filename, import->doc); 988 import = import->next; 989 } 990 991 #if 0 992 printf("---- main doc ----\n"); 993 test_document(mainDoc); 994 995 import = g_imports; 996 while (import) { 997 printf("---- import doc ----\n"); 998 test_document(import->doc); 999 import = import->next; 1000 } 1001 NAMES.Dump(); 1002 #endif 1003 1004 // check the referenced types in mainDoc to make sure we've imported them 1005 err |= check_types(options.inputFileName.c_str(), mainDoc); 1006 1007 // finally, there really only needs to be one thing in mainDoc, and it 1008 // needs to be an interface. 1009 bool onlyParcelable = false; 1010 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable); 1011 1012 // If this includes an interface definition, then assign method ids and validate. 1013 if (!onlyParcelable) { 1014 err |= check_and_assign_method_ids(options.inputFileName.c_str(), 1015 ((interface_type*)mainDoc)->interface_items); 1016 } 1017 1018 // after this, there shouldn't be any more errors because of the 1019 // input. 1020 if (err != 0 || mainDoc == NULL) { 1021 return 1; 1022 } 1023 1024 // if needed, generate the outputFileName from the outputBaseFolder 1025 if (options.outputFileName.length() == 0 && 1026 options.outputBaseFolder.length() > 0) { 1027 options.outputFileName = generate_outputFileName(options, mainDoc); 1028 } 1029 1030 // if we were asked to, generate a make dependency file 1031 // unless it's a parcelable *and* it's supposed to fail on parcelable 1032 if ((options.autoDepFile || options.depFileName != "") && 1033 !(onlyParcelable && options.failOnParcelable)) { 1034 // make sure the folders of the output file all exists 1035 check_outputFilePath(options.outputFileName); 1036 generate_dep_file(options, mainDoc); 1037 } 1038 1039 // they didn't ask to fail on parcelables, so just exit quietly. 1040 if (onlyParcelable && !options.failOnParcelable) { 1041 return 0; 1042 } 1043 1044 // make sure the folders of the output file all exists 1045 check_outputFilePath(options.outputFileName); 1046 1047 err = generate_java(options.outputFileName, options.inputFileName.c_str(), 1048 (interface_type*)mainDoc); 1049 1050 return err; 1051 } 1052 1053 static int 1054 preprocess_aidl(const Options& options) 1055 { 1056 vector<string> lines; 1057 int err; 1058 1059 // read files 1060 int N = options.filesToPreprocess.size(); 1061 for (int i=0; i<N; i++) { 1062 g_callbacks = &g_mainCallbacks; 1063 err = parse_aidl(options.filesToPreprocess[i].c_str()); 1064 if (err != 0) { 1065 return err; 1066 } 1067 document_item_type* doc = g_document; 1068 string line; 1069 if (doc->item_type == USER_DATA_TYPE) { 1070 user_data_type* parcelable = (user_data_type*)doc; 1071 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) { 1072 line = "parcelable "; 1073 } 1074 if ((parcelable->flattening_methods & RPC_DATA) != 0) { 1075 line = "flattenable "; 1076 } 1077 if (parcelable->package) { 1078 line += parcelable->package; 1079 line += '.'; 1080 } 1081 line += parcelable->name.data; 1082 } else { 1083 line = "interface "; 1084 interface_type* iface = (interface_type*)doc; 1085 if (iface->package) { 1086 line += iface->package; 1087 line += '.'; 1088 } 1089 line += iface->name.data; 1090 } 1091 line += ";\n"; 1092 lines.push_back(line); 1093 } 1094 1095 // write preprocessed file 1096 int fd = open( options.outputFileName.c_str(), 1097 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 1098 #ifdef HAVE_MS_C_RUNTIME 1099 _S_IREAD|_S_IWRITE); 1100 #else 1101 S_IRUSR|S_IWUSR|S_IRGRP); 1102 #endif 1103 if (fd == -1) { 1104 fprintf(stderr, "aidl: could not open file for write: %s\n", 1105 options.outputFileName.c_str()); 1106 return 1; 1107 } 1108 1109 N = lines.size(); 1110 for (int i=0; i<N; i++) { 1111 const string& s = lines[i]; 1112 int len = s.length(); 1113 if (len != write(fd, s.c_str(), len)) { 1114 fprintf(stderr, "aidl: error writing to file %s\n", 1115 options.outputFileName.c_str()); 1116 close(fd); 1117 unlink(options.outputFileName.c_str()); 1118 return 1; 1119 } 1120 } 1121 1122 close(fd); 1123 return 0; 1124 } 1125 1126 // ========================================================== 1127 int 1128 main(int argc, const char **argv) 1129 { 1130 Options options; 1131 int result = parse_options(argc, argv, &options); 1132 if (result) { 1133 return result; 1134 } 1135 1136 switch (options.task) 1137 { 1138 case COMPILE_AIDL: 1139 return compile_aidl(options); 1140 case PREPROCESS_AIDL: 1141 return preprocess_aidl(options); 1142 } 1143 fprintf(stderr, "aidl: internal error\n"); 1144 return 1; 1145 } 1146