1 #include "generate_java.h" 2 #include "AST.h" 3 #include "Type.h" 4 #include <string.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 9 // ================================================= 10 class VariableFactory 11 { 12 public: 13 VariableFactory(const string& base); // base must be short 14 Variable* Get(Type* type); 15 Variable* Get(int index); 16 private: 17 vector<Variable*> m_vars; 18 string m_base; 19 int m_index; 20 }; 21 22 VariableFactory::VariableFactory(const string& base) 23 :m_base(base), 24 m_index(0) 25 { 26 } 27 28 Variable* 29 VariableFactory::Get(Type* type) 30 { 31 char name[100]; 32 sprintf(name, "%s%d", m_base.c_str(), m_index); 33 m_index++; 34 Variable* v = new Variable(type, name); 35 m_vars.push_back(v); 36 return v; 37 } 38 39 Variable* 40 VariableFactory::Get(int index) 41 { 42 return m_vars[index]; 43 } 44 45 // ================================================= 46 class StubClass : public Class 47 { 48 public: 49 StubClass(Type* type, Type* interfaceType); 50 virtual ~StubClass(); 51 52 Variable* transact_code; 53 Variable* transact_data; 54 Variable* transact_reply; 55 Variable* transact_flags; 56 SwitchStatement* transact_switch; 57 private: 58 void make_as_interface(Type* interfaceType); 59 }; 60 61 StubClass::StubClass(Type* type, Type* interfaceType) 62 :Class() 63 { 64 this->comment = "/** Local-side IPC implementation stub class. */"; 65 this->modifiers = PUBLIC | ABSTRACT | STATIC; 66 this->what = Class::CLASS; 67 this->type = type; 68 this->extends = BINDER_NATIVE_TYPE; 69 this->interfaces.push_back(interfaceType); 70 71 // descriptor 72 Field* descriptor = new Field(STATIC | FINAL | PRIVATE, 73 new Variable(STRING_TYPE, "DESCRIPTOR")); 74 descriptor->value = "\"" + interfaceType->QualifiedName() + "\""; 75 this->elements.push_back(descriptor); 76 77 // ctor 78 Method* ctor = new Method; 79 ctor->modifiers = PUBLIC; 80 ctor->comment = "/** Construct the stub at attach it to the " 81 "interface. */"; 82 ctor->name = "Stub"; 83 ctor->statements = new StatementBlock; 84 MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface", 85 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR")); 86 ctor->statements->Add(attach); 87 this->elements.push_back(ctor); 88 89 // asInterface 90 make_as_interface(interfaceType); 91 92 // asBinder 93 Method* asBinder = new Method; 94 asBinder->modifiers = PUBLIC; 95 asBinder->returnType = IBINDER_TYPE; 96 asBinder->name = "asBinder"; 97 asBinder->statements = new StatementBlock; 98 asBinder->statements->Add(new ReturnStatement(THIS_VALUE)); 99 this->elements.push_back(asBinder); 100 101 // onTransact 102 this->transact_code = new Variable(INT_TYPE, "code"); 103 this->transact_data = new Variable(PARCEL_TYPE, "data"); 104 this->transact_reply = new Variable(PARCEL_TYPE, "reply"); 105 this->transact_flags = new Variable(INT_TYPE, "flags"); 106 Method* onTransact = new Method; 107 onTransact->modifiers = PUBLIC | OVERRIDE; 108 onTransact->returnType = BOOLEAN_TYPE; 109 onTransact->name = "onTransact"; 110 onTransact->parameters.push_back(this->transact_code); 111 onTransact->parameters.push_back(this->transact_data); 112 onTransact->parameters.push_back(this->transact_reply); 113 onTransact->parameters.push_back(this->transact_flags); 114 onTransact->statements = new StatementBlock; 115 onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE); 116 this->elements.push_back(onTransact); 117 this->transact_switch = new SwitchStatement(this->transact_code); 118 119 onTransact->statements->Add(this->transact_switch); 120 MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4, 121 this->transact_code, this->transact_data, 122 this->transact_reply, this->transact_flags); 123 onTransact->statements->Add(new ReturnStatement(superCall)); 124 } 125 126 StubClass::~StubClass() 127 { 128 } 129 130 void 131 StubClass::make_as_interface(Type *interfaceType) 132 { 133 Variable* obj = new Variable(IBINDER_TYPE, "obj"); 134 135 Method* m = new Method; 136 m->comment = "/**\n * Cast an IBinder object into an "; 137 m->comment += interfaceType->QualifiedName(); 138 m->comment += " interface,\n"; 139 m->comment += " * generating a proxy if needed.\n */"; 140 m->modifiers = PUBLIC | STATIC; 141 m->returnType = interfaceType; 142 m->name = "asInterface"; 143 m->parameters.push_back(obj); 144 m->statements = new StatementBlock; 145 146 IfStatement* ifstatement = new IfStatement(); 147 ifstatement->expression = new Comparison(obj, "==", NULL_VALUE); 148 ifstatement->statements = new StatementBlock; 149 ifstatement->statements->Add(new ReturnStatement(NULL_VALUE)); 150 m->statements->Add(ifstatement); 151 152 // IInterface iin = obj.queryLocalInterface(DESCRIPTOR) 153 MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface"); 154 queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR")); 155 IInterfaceType* iinType = new IInterfaceType(); 156 Variable *iin = new Variable(iinType, "iin"); 157 VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType); 158 m->statements->Add(iinVd); 159 160 // Ensure the instance type of the local object is as expected. 161 // One scenario where this is needed is if another package (with a 162 // different class loader) runs in the same process as the service. 163 164 // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin; 165 Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE); 166 Comparison* instOfCheck = new Comparison(iin, " instanceof ", 167 new LiteralExpression(interfaceType->QualifiedName())); 168 IfStatement* instOfStatement = new IfStatement(); 169 instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck); 170 instOfStatement->statements = new StatementBlock; 171 instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin))); 172 m->statements->Add(instOfStatement); 173 174 string proxyType = interfaceType->QualifiedName(); 175 proxyType += ".Stub.Proxy"; 176 NewExpression* ne = new NewExpression(NAMES.Find(proxyType)); 177 ne->arguments.push_back(obj); 178 m->statements->Add(new ReturnStatement(ne)); 179 180 this->elements.push_back(m); 181 } 182 183 184 185 // ================================================= 186 class ProxyClass : public Class 187 { 188 public: 189 ProxyClass(Type* type, InterfaceType* interfaceType); 190 virtual ~ProxyClass(); 191 192 Variable* mRemote; 193 bool mOneWay; 194 }; 195 196 ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType) 197 :Class() 198 { 199 this->modifiers = PRIVATE | STATIC; 200 this->what = Class::CLASS; 201 this->type = type; 202 this->interfaces.push_back(interfaceType); 203 204 mOneWay = interfaceType->OneWay(); 205 206 // IBinder mRemote 207 mRemote = new Variable(IBINDER_TYPE, "mRemote"); 208 this->elements.push_back(new Field(PRIVATE, mRemote)); 209 210 // Proxy() 211 Variable* remote = new Variable(IBINDER_TYPE, "remote"); 212 Method* ctor = new Method; 213 ctor->name = "Proxy"; 214 ctor->statements = new StatementBlock; 215 ctor->parameters.push_back(remote); 216 ctor->statements->Add(new Assignment(mRemote, remote)); 217 this->elements.push_back(ctor); 218 219 // IBinder asBinder() 220 Method* asBinder = new Method; 221 asBinder->modifiers = PUBLIC; 222 asBinder->returnType = IBINDER_TYPE; 223 asBinder->name = "asBinder"; 224 asBinder->statements = new StatementBlock; 225 asBinder->statements->Add(new ReturnStatement(mRemote)); 226 this->elements.push_back(asBinder); 227 } 228 229 ProxyClass::~ProxyClass() 230 { 231 } 232 233 // ================================================= 234 static string 235 gather_comments(extra_text_type* extra) 236 { 237 string s; 238 while (extra) { 239 if (extra->which == SHORT_COMMENT) { 240 s += extra->data; 241 } 242 else if (extra->which == LONG_COMMENT) { 243 s += "/*"; 244 s += extra->data; 245 s += "*/"; 246 } 247 extra = extra->next; 248 } 249 return s; 250 } 251 252 static string 253 append(const char* a, const char* b) 254 { 255 string s = a; 256 s += b; 257 return s; 258 } 259 260 static void 261 generate_new_array(Type* t, StatementBlock* addTo, Variable* v, 262 Variable* parcel) 263 { 264 Variable* len = new Variable(INT_TYPE, v->name + "_length"); 265 addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt"))); 266 IfStatement* lencheck = new IfStatement(); 267 lencheck->expression = new Comparison(len, "<", new LiteralExpression("0")); 268 lencheck->statements->Add(new Assignment(v, NULL_VALUE)); 269 lencheck->elseif = new IfStatement(); 270 lencheck->elseif->statements->Add(new Assignment(v, 271 new NewArrayExpression(t, len))); 272 addTo->Add(lencheck); 273 } 274 275 static void 276 generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v, 277 Variable* parcel, int flags) 278 { 279 if (v->dimension == 0) { 280 t->WriteToParcel(addTo, v, parcel, flags); 281 } 282 if (v->dimension == 1) { 283 t->WriteArrayToParcel(addTo, v, parcel, flags); 284 } 285 } 286 287 static void 288 generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v, 289 Variable* parcel, Variable** cl) 290 { 291 if (v->dimension == 0) { 292 t->CreateFromParcel(addTo, v, parcel, cl); 293 } 294 if (v->dimension == 1) { 295 t->CreateArrayFromParcel(addTo, v, parcel, cl); 296 } 297 } 298 299 static void 300 generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v, 301 Variable* parcel, Variable** cl) 302 { 303 if (v->dimension == 0) { 304 t->ReadFromParcel(addTo, v, parcel, cl); 305 } 306 if (v->dimension == 1) { 307 t->ReadArrayFromParcel(addTo, v, parcel, cl); 308 } 309 } 310 311 312 static void 313 generate_method(const method_type* method, Class* interface, 314 StubClass* stubClass, ProxyClass* proxyClass, int index) 315 { 316 arg_type* arg; 317 int i; 318 bool hasOutParams = false; 319 320 const bool oneway = proxyClass->mOneWay || method->oneway; 321 322 // == the TRANSACT_ constant ============================================= 323 string transactCodeName = "TRANSACTION_"; 324 transactCodeName += method->name.data; 325 326 char transactCodeValue[50]; 327 sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index); 328 329 Field* transactCode = new Field(STATIC | FINAL, 330 new Variable(INT_TYPE, transactCodeName)); 331 transactCode->value = transactCodeValue; 332 stubClass->elements.push_back(transactCode); 333 334 // == the declaration in the interface =================================== 335 Method* decl = new Method; 336 decl->comment = gather_comments(method->comments_token->extra); 337 decl->modifiers = PUBLIC; 338 decl->returnType = NAMES.Search(method->type.type.data); 339 decl->returnTypeDimension = method->type.dimension; 340 decl->name = method->name.data; 341 342 arg = method->args; 343 while (arg != NULL) { 344 decl->parameters.push_back(new Variable( 345 NAMES.Search(arg->type.type.data), arg->name.data, 346 arg->type.dimension)); 347 arg = arg->next; 348 } 349 350 decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE); 351 352 interface->elements.push_back(decl); 353 354 // == the stub method ==================================================== 355 356 Case* c = new Case(transactCodeName); 357 358 MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data); 359 360 // interface token validation is the very first thing we do 361 c->statements->Add(new MethodCall(stubClass->transact_data, 362 "enforceInterface", 1, new LiteralExpression("DESCRIPTOR"))); 363 364 // args 365 Variable* cl = NULL; 366 VariableFactory stubArgs("_arg"); 367 arg = method->args; 368 while (arg != NULL) { 369 Type* t = NAMES.Search(arg->type.type.data); 370 Variable* v = stubArgs.Get(t); 371 v->dimension = arg->type.dimension; 372 373 c->statements->Add(new VariableDeclaration(v)); 374 375 if (convert_direction(arg->direction.data) & IN_PARAMETER) { 376 generate_create_from_parcel(t, c->statements, v, 377 stubClass->transact_data, &cl); 378 } else { 379 if (arg->type.dimension == 0) { 380 c->statements->Add(new Assignment( 381 v, new NewExpression(v->type))); 382 } 383 else if (arg->type.dimension == 1) { 384 generate_new_array(v->type, c->statements, v, 385 stubClass->transact_data); 386 } 387 else { 388 fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, 389 __LINE__); 390 } 391 } 392 393 realCall->arguments.push_back(v); 394 395 arg = arg->next; 396 } 397 398 // the real call 399 Variable* _result = NULL; 400 if (0 == strcmp(method->type.type.data, "void")) { 401 c->statements->Add(realCall); 402 403 if (!oneway) { 404 // report that there were no exceptions 405 MethodCall* ex = new MethodCall(stubClass->transact_reply, 406 "writeNoException", 0); 407 c->statements->Add(ex); 408 } 409 } else { 410 _result = new Variable(decl->returnType, "_result", 411 decl->returnTypeDimension); 412 c->statements->Add(new VariableDeclaration(_result, realCall)); 413 414 if (!oneway) { 415 // report that there were no exceptions 416 MethodCall* ex = new MethodCall(stubClass->transact_reply, 417 "writeNoException", 0); 418 c->statements->Add(ex); 419 } 420 421 // marshall the return value 422 generate_write_to_parcel(decl->returnType, c->statements, _result, 423 stubClass->transact_reply, 424 Type::PARCELABLE_WRITE_RETURN_VALUE); 425 } 426 427 // out parameters 428 i = 0; 429 arg = method->args; 430 while (arg != NULL) { 431 Type* t = NAMES.Search(arg->type.type.data); 432 Variable* v = stubArgs.Get(i++); 433 434 if (convert_direction(arg->direction.data) & OUT_PARAMETER) { 435 generate_write_to_parcel(t, c->statements, v, 436 stubClass->transact_reply, 437 Type::PARCELABLE_WRITE_RETURN_VALUE); 438 hasOutParams = true; 439 } 440 441 arg = arg->next; 442 } 443 444 // return true 445 c->statements->Add(new ReturnStatement(TRUE_VALUE)); 446 stubClass->transact_switch->cases.push_back(c); 447 448 // == the proxy method =================================================== 449 Method* proxy = new Method; 450 proxy->comment = gather_comments(method->comments_token->extra); 451 proxy->modifiers = PUBLIC; 452 proxy->returnType = NAMES.Search(method->type.type.data); 453 proxy->returnTypeDimension = method->type.dimension; 454 proxy->name = method->name.data; 455 proxy->statements = new StatementBlock; 456 arg = method->args; 457 while (arg != NULL) { 458 proxy->parameters.push_back(new Variable( 459 NAMES.Search(arg->type.type.data), arg->name.data, 460 arg->type.dimension)); 461 arg = arg->next; 462 } 463 proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE); 464 proxyClass->elements.push_back(proxy); 465 466 // the parcels 467 Variable* _data = new Variable(PARCEL_TYPE, "_data"); 468 proxy->statements->Add(new VariableDeclaration(_data, 469 new MethodCall(PARCEL_TYPE, "obtain"))); 470 Variable* _reply = NULL; 471 if (!oneway) { 472 _reply = new Variable(PARCEL_TYPE, "_reply"); 473 proxy->statements->Add(new VariableDeclaration(_reply, 474 new MethodCall(PARCEL_TYPE, "obtain"))); 475 } 476 477 // the return value 478 _result = NULL; 479 if (0 != strcmp(method->type.type.data, "void")) { 480 _result = new Variable(proxy->returnType, "_result", 481 method->type.dimension); 482 proxy->statements->Add(new VariableDeclaration(_result)); 483 } 484 485 // try and finally 486 TryStatement* tryStatement = new TryStatement(); 487 proxy->statements->Add(tryStatement); 488 FinallyStatement* finallyStatement = new FinallyStatement(); 489 proxy->statements->Add(finallyStatement); 490 491 // the interface identifier token: the DESCRIPTOR constant, marshalled as a string 492 tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken", 493 1, new LiteralExpression("DESCRIPTOR"))); 494 495 // the parameters 496 arg = method->args; 497 while (arg != NULL) { 498 Type* t = NAMES.Search(arg->type.type.data); 499 Variable* v = new Variable(t, arg->name.data, arg->type.dimension); 500 int dir = convert_direction(arg->direction.data); 501 if (dir == OUT_PARAMETER && arg->type.dimension != 0) { 502 IfStatement* checklen = new IfStatement(); 503 checklen->expression = new Comparison(v, "==", NULL_VALUE); 504 checklen->statements->Add(new MethodCall(_data, "writeInt", 1, 505 new LiteralExpression("-1"))); 506 checklen->elseif = new IfStatement(); 507 checklen->elseif->statements->Add(new MethodCall(_data, "writeInt", 508 1, new FieldVariable(v, "length"))); 509 tryStatement->statements->Add(checklen); 510 } 511 else if (dir & IN_PARAMETER) { 512 generate_write_to_parcel(t, tryStatement->statements, v, _data, 0); 513 } 514 arg = arg->next; 515 } 516 517 // the transact call 518 MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4, 519 new LiteralExpression("Stub." + transactCodeName), 520 _data, _reply ? _reply : NULL_VALUE, 521 new LiteralExpression( 522 oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0")); 523 tryStatement->statements->Add(call); 524 525 // throw back exceptions. 526 if (_reply) { 527 MethodCall* ex = new MethodCall(_reply, "readException", 0); 528 tryStatement->statements->Add(ex); 529 } 530 531 // returning and cleanup 532 if (_reply != NULL) { 533 if (_result != NULL) { 534 generate_create_from_parcel(proxy->returnType, 535 tryStatement->statements, _result, _reply, &cl); 536 } 537 538 // the out/inout parameters 539 arg = method->args; 540 while (arg != NULL) { 541 Type* t = NAMES.Search(arg->type.type.data); 542 Variable* v = new Variable(t, arg->name.data, arg->type.dimension); 543 if (convert_direction(arg->direction.data) & OUT_PARAMETER) { 544 generate_read_from_parcel(t, tryStatement->statements, 545 v, _reply, &cl); 546 } 547 arg = arg->next; 548 } 549 550 finallyStatement->statements->Add(new MethodCall(_reply, "recycle")); 551 } 552 finallyStatement->statements->Add(new MethodCall(_data, "recycle")); 553 554 if (_result != NULL) { 555 proxy->statements->Add(new ReturnStatement(_result)); 556 } 557 } 558 559 static void 560 generate_interface_descriptors(StubClass* stub, ProxyClass* proxy) 561 { 562 // the interface descriptor transaction handler 563 Case* c = new Case("INTERFACE_TRANSACTION"); 564 c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 565 1, new LiteralExpression("DESCRIPTOR"))); 566 c->statements->Add(new ReturnStatement(TRUE_VALUE)); 567 stub->transact_switch->cases.push_back(c); 568 569 // and the proxy-side method returning the descriptor directly 570 Method* getDesc = new Method; 571 getDesc->modifiers = PUBLIC; 572 getDesc->returnType = STRING_TYPE; 573 getDesc->returnTypeDimension = 0; 574 getDesc->name = "getInterfaceDescriptor"; 575 getDesc->statements = new StatementBlock; 576 getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); 577 proxy->elements.push_back(getDesc); 578 } 579 580 static Class* 581 generate_interface_class(const interface_type* iface) 582 { 583 InterfaceType* interfaceType = static_cast<InterfaceType*>( 584 NAMES.Find(iface->package, iface->name.data)); 585 586 // the interface class 587 Class* interface = new Class; 588 interface->comment = gather_comments(iface->comments_token->extra); 589 interface->modifiers = PUBLIC; 590 interface->what = Class::INTERFACE; 591 interface->type = interfaceType; 592 interface->interfaces.push_back(IINTERFACE_TYPE); 593 594 // the stub inner class 595 StubClass* stub = new StubClass( 596 NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()), 597 interfaceType); 598 interface->elements.push_back(stub); 599 600 // the proxy inner class 601 ProxyClass* proxy = new ProxyClass( 602 NAMES.Find(iface->package, 603 append(iface->name.data, ".Stub.Proxy").c_str()), 604 interfaceType); 605 stub->elements.push_back(proxy); 606 607 // stub and proxy support for getInterfaceDescriptor() 608 generate_interface_descriptors(stub, proxy); 609 610 // all the declared methods of the interface 611 int index = 0; 612 interface_item_type* item = iface->interface_items; 613 while (item != NULL) { 614 if (item->item_type == METHOD_TYPE) { 615 generate_method((method_type*)item, interface, stub, proxy, index); 616 } 617 item = item->next; 618 index++; 619 } 620 621 return interface; 622 } 623 624 int 625 generate_java(const string& filename, const string& originalSrc, 626 interface_type* iface) 627 { 628 Document* document = new Document; 629 document->comment = ""; 630 if (iface->package) document->package = iface->package; 631 document->originalSrc = originalSrc; 632 document->classes.push_back(generate_interface_class(iface)); 633 634 // printf("outputting... filename=%s\n", filename.c_str()); 635 FILE* to; 636 if (filename == "-") { 637 to = stdout; 638 } else { 639 /* open file in binary mode to ensure that the tool produces the 640 * same output on all platforms !! 641 */ 642 to = fopen(filename.c_str(), "wb"); 643 if (to == NULL) { 644 fprintf(stderr, "unable to open %s for write\n", filename.c_str()); 645 return 1; 646 } 647 } 648 649 document->Write(to); 650 651 fclose(to); 652 return 0; 653 } 654 655