aidl.cpp revision b30296b5fda75bf383c7ab3f567eb41820747869
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 32using namespace std; 33 34static void 35test_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// ========================================================== 76int 77convert_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// ========================================================== 92struct 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 101document_item_type* g_document = NULL; 102import_info* g_imports = NULL; 103 104static void 105main_document_parsed(document_item_type* d) 106{ 107 g_document = d; 108} 109 110static void 111main_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 124static ParserCallbacks g_mainCallbacks = { 125 &main_document_parsed, 126 &main_import_parsed 127}; 128 129char* 130parse_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// ========================================================== 158static void 159import_import_parsed(buffer_type* statement) 160{ 161} 162 163static ParserCallbacks g_importCallbacks = { 164 &main_document_parsed, 165 &import_import_parsed 166}; 167 168// ========================================================== 169static int 170check_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 247static int 248check_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// ========================================================== 272static const char* 273kind_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 286static char* 287rfind(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 299static int 300gather_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// ========================================================== 386static bool 387matches_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 410static int 411check_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 540next: 541 index++; 542 arg = arg->next; 543 } 544 545 return err; 546} 547 548static int 549check_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// ========================================================== 588static int 589exactly_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// ========================================================== 632void 633generate_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// ========================================================== 690static string 691generate_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// ========================================================== 722static string 723generate_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// ========================================================== 743static void 744check_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// ========================================================== 762static int 763parse_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 fclose(f); 851 return 1; 852 } 853 err = gather_types(filename.c_str(), doc); 854 lineno++; 855 } 856 857 if (!feof(f)) { 858 fprintf(stderr, "%s:%d: error reading file, line to long.\n", 859 filename.c_str(), lineno); 860 return 1; 861 } 862 863 fclose(f); 864 return 0; 865} 866 867static int 868check_and_assign_method_ids(const char * filename, interface_item_type* first_item) 869{ 870 // Check whether there are any methods with manually assigned id's and any that are not. 871 // Either all method id's must be manually assigned or all of them must not. 872 // Also, check for duplicates of user set id's and that the id's are within the proper bounds. 873 set<int> usedIds; 874 interface_item_type* item = first_item; 875 bool hasUnassignedIds = false; 876 bool hasAssignedIds = false; 877 while (item != NULL) { 878 if (item->item_type == METHOD_TYPE) { 879 method_type* method_item = (method_type*)item; 880 if (method_item->hasId) { 881 hasAssignedIds = true; 882 method_item->assigned_id = atoi(method_item->id.data); 883 // Ensure that the user set id is not duplicated. 884 if (usedIds.find(method_item->assigned_id) != usedIds.end()) { 885 // We found a duplicate id, so throw an error. 886 fprintf(stderr, 887 "%s:%d Found duplicate method id (%d) for method: %s\n", 888 filename, method_item->id.lineno, 889 method_item->assigned_id, method_item->name.data); 890 return 1; 891 } 892 // Ensure that the user set id is within the appropriate limits 893 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID || 894 method_item->assigned_id > MAX_USER_SET_METHOD_ID) { 895 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n", 896 filename, method_item->id.lineno, 897 method_item->assigned_id, method_item->name.data); 898 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n", 899 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID); 900 return 1; 901 } 902 usedIds.insert(method_item->assigned_id); 903 } else { 904 hasUnassignedIds = true; 905 } 906 if (hasAssignedIds && hasUnassignedIds) { 907 fprintf(stderr, 908 "%s: You must either assign id's to all methods or to none of them.\n", 909 filename); 910 return 1; 911 } 912 } 913 item = item->next; 914 } 915 916 // In the case that all methods have unassigned id's, set a unique id for them. 917 if (hasUnassignedIds) { 918 int newId = 0; 919 item = first_item; 920 while (item != NULL) { 921 if (item->item_type == METHOD_TYPE) { 922 method_type* method_item = (method_type*)item; 923 method_item->assigned_id = newId++; 924 } 925 item = item->next; 926 } 927 } 928 929 // success 930 return 0; 931} 932 933// ========================================================== 934static int 935compile_aidl(Options& options) 936{ 937 int err = 0, N; 938 939 set_import_paths(options.importPaths); 940 941 register_base_types(); 942 943 // import the preprocessed file 944 N = options.preprocessedFiles.size(); 945 for (int i=0; i<N; i++) { 946 const string& s = options.preprocessedFiles[i]; 947 err |= parse_preprocessed_file(s); 948 } 949 if (err != 0) { 950 return err; 951 } 952 953 // parse the main file 954 g_callbacks = &g_mainCallbacks; 955 err = parse_aidl(options.inputFileName.c_str()); 956 document_item_type* mainDoc = g_document; 957 g_document = NULL; 958 959 // parse the imports 960 g_callbacks = &g_mainCallbacks; 961 import_info* import = g_imports; 962 while (import) { 963 if (NAMES.Find(import->neededClass) == NULL) { 964 import->filename = find_import_file(import->neededClass); 965 if (!import->filename) { 966 fprintf(stderr, "%s:%d: couldn't find import for class %s\n", 967 import->from, import->statement.lineno, 968 import->neededClass); 969 err |= 1; 970 } else { 971 err |= parse_aidl(import->filename); 972 import->doc = g_document; 973 if (import->doc == NULL) { 974 err |= 1; 975 } 976 } 977 } 978 import = import->next; 979 } 980 // bail out now if parsing wasn't successful 981 if (err != 0 || mainDoc == NULL) { 982 //fprintf(stderr, "aidl: parsing failed, stopping.\n"); 983 return 1; 984 } 985 986 // complain about ones that aren't in the right files 987 err |= check_filenames(options.inputFileName.c_str(), mainDoc); 988 import = g_imports; 989 while (import) { 990 err |= check_filenames(import->filename, import->doc); 991 import = import->next; 992 } 993 994 // gather the types that have been declared 995 err |= gather_types(options.inputFileName.c_str(), mainDoc); 996 import = g_imports; 997 while (import) { 998 err |= gather_types(import->filename, import->doc); 999 import = import->next; 1000 } 1001 1002#if 0 1003 printf("---- main doc ----\n"); 1004 test_document(mainDoc); 1005 1006 import = g_imports; 1007 while (import) { 1008 printf("---- import doc ----\n"); 1009 test_document(import->doc); 1010 import = import->next; 1011 } 1012 NAMES.Dump(); 1013#endif 1014 1015 // check the referenced types in mainDoc to make sure we've imported them 1016 err |= check_types(options.inputFileName.c_str(), mainDoc); 1017 1018 // finally, there really only needs to be one thing in mainDoc, and it 1019 // needs to be an interface. 1020 bool onlyParcelable = false; 1021 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable); 1022 1023 // If this includes an interface definition, then assign method ids and validate. 1024 if (!onlyParcelable) { 1025 err |= check_and_assign_method_ids(options.inputFileName.c_str(), 1026 ((interface_type*)mainDoc)->interface_items); 1027 } 1028 1029 // after this, there shouldn't be any more errors because of the 1030 // input. 1031 if (err != 0 || mainDoc == NULL) { 1032 return 1; 1033 } 1034 1035 // if needed, generate the outputFileName from the outputBaseFolder 1036 if (options.outputFileName.length() == 0 && 1037 options.outputBaseFolder.length() > 0) { 1038 options.outputFileName = generate_outputFileName(options, mainDoc); 1039 } 1040 1041 // if we were asked to, generate a make dependency file 1042 // unless it's a parcelable *and* it's supposed to fail on parcelable 1043 if ((options.autoDepFile || options.depFileName != "") && 1044 !(onlyParcelable && options.failOnParcelable)) { 1045 // make sure the folders of the output file all exists 1046 check_outputFilePath(options.outputFileName); 1047 generate_dep_file(options, mainDoc); 1048 } 1049 1050 // they didn't ask to fail on parcelables, so just exit quietly. 1051 if (onlyParcelable && !options.failOnParcelable) { 1052 return 0; 1053 } 1054 1055 // make sure the folders of the output file all exists 1056 check_outputFilePath(options.outputFileName); 1057 1058 err = generate_java(options.outputFileName, options.inputFileName.c_str(), 1059 (interface_type*)mainDoc); 1060 1061 return err; 1062} 1063 1064static int 1065preprocess_aidl(const Options& options) 1066{ 1067 vector<string> lines; 1068 int err; 1069 1070 // read files 1071 int N = options.filesToPreprocess.size(); 1072 for (int i=0; i<N; i++) { 1073 g_callbacks = &g_mainCallbacks; 1074 err = parse_aidl(options.filesToPreprocess[i].c_str()); 1075 if (err != 0) { 1076 return err; 1077 } 1078 document_item_type* doc = g_document; 1079 string line; 1080 if (doc->item_type == USER_DATA_TYPE) { 1081 user_data_type* parcelable = (user_data_type*)doc; 1082 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) { 1083 line = "parcelable "; 1084 } 1085 if ((parcelable->flattening_methods & RPC_DATA) != 0) { 1086 line = "flattenable "; 1087 } 1088 if (parcelable->package) { 1089 line += parcelable->package; 1090 line += '.'; 1091 } 1092 line += parcelable->name.data; 1093 } else { 1094 line = "interface "; 1095 interface_type* iface = (interface_type*)doc; 1096 if (iface->package) { 1097 line += iface->package; 1098 line += '.'; 1099 } 1100 line += iface->name.data; 1101 } 1102 line += ";\n"; 1103 lines.push_back(line); 1104 } 1105 1106 // write preprocessed file 1107 int fd = open( options.outputFileName.c_str(), 1108 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 1109#ifdef HAVE_MS_C_RUNTIME 1110 _S_IREAD|_S_IWRITE); 1111#else 1112 S_IRUSR|S_IWUSR|S_IRGRP); 1113#endif 1114 if (fd == -1) { 1115 fprintf(stderr, "aidl: could not open file for write: %s\n", 1116 options.outputFileName.c_str()); 1117 return 1; 1118 } 1119 1120 N = lines.size(); 1121 for (int i=0; i<N; i++) { 1122 const string& s = lines[i]; 1123 int len = s.length(); 1124 if (len != write(fd, s.c_str(), len)) { 1125 fprintf(stderr, "aidl: error writing to file %s\n", 1126 options.outputFileName.c_str()); 1127 close(fd); 1128 unlink(options.outputFileName.c_str()); 1129 return 1; 1130 } 1131 } 1132 1133 close(fd); 1134 return 0; 1135} 1136 1137// ========================================================== 1138int 1139main(int argc, const char **argv) 1140{ 1141 Options options; 1142 int result = parse_options(argc, argv, &options); 1143 if (result) { 1144 return result; 1145 } 1146 1147 switch (options.task) 1148 { 1149 case COMPILE_AIDL: 1150 return compile_aidl(options); 1151 case PREPROCESS_AIDL: 1152 return preprocess_aidl(options); 1153 } 1154 fprintf(stderr, "aidl: internal error\n"); 1155 return 1; 1156} 1157