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