generate_java.cpp revision 5887f2199a6285e3af36aaa5e446bcdf2d54f408
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// ================================================= 10class VariableFactory 11{ 12public: 13 VariableFactory(const string& base); // base must be short 14 Variable* Get(Type* type); 15 Variable* Get(int index); 16private: 17 vector<Variable*> m_vars; 18 string m_base; 19 int m_index; 20}; 21 22VariableFactory::VariableFactory(const string& base) 23 :m_base(base), 24 m_index(0) 25{ 26} 27 28Variable* 29VariableFactory::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 39Variable* 40VariableFactory::Get(int index) 41{ 42 return m_vars[index]; 43} 44 45// ================================================= 46class StubClass : public Class 47{ 48public: 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; 57private: 58 void make_as_interface(Type* interfaceType); 59}; 60 61StubClass::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 126StubClass::~StubClass() 127{ 128} 129 130void 131StubClass::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// ================================================= 186class ProxyClass : public Class 187{ 188public: 189 ProxyClass(Type* type, InterfaceType* interfaceType); 190 virtual ~ProxyClass(); 191 192 Variable* mRemote; 193 bool mOneWay; 194}; 195 196ProxyClass::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 229ProxyClass::~ProxyClass() 230{ 231} 232 233// ================================================= 234static string 235gather_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 252static string 253append(const char* a, const char* b) 254{ 255 string s = a; 256 s += b; 257 return s; 258} 259 260static void 261generate_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 275static void 276generate_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 287static void 288generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v, 289 Variable* parcel) 290{ 291 if (v->dimension == 0) { 292 t->CreateFromParcel(addTo, v, parcel); 293 } 294 if (v->dimension == 1) { 295 t->CreateArrayFromParcel(addTo, v, parcel); 296 } 297} 298 299static void 300generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v, 301 Variable* parcel) 302{ 303 if (v->dimension == 0) { 304 t->ReadFromParcel(addTo, v, parcel); 305 } 306 if (v->dimension == 1) { 307 t->ReadArrayFromParcel(addTo, v, parcel); 308 } 309} 310 311 312static void 313generate_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 VariableFactory stubArgs("_arg"); 366 arg = method->args; 367 while (arg != NULL) { 368 Type* t = NAMES.Search(arg->type.type.data); 369 Variable* v = stubArgs.Get(t); 370 v->dimension = arg->type.dimension; 371 372 c->statements->Add(new VariableDeclaration(v)); 373 374 if (convert_direction(arg->direction.data) & IN_PARAMETER) { 375 generate_create_from_parcel(t, c->statements, v, 376 stubClass->transact_data); 377 } else { 378 if (arg->type.dimension == 0) { 379 c->statements->Add(new Assignment( 380 v, new NewExpression(v->type))); 381 } 382 else if (arg->type.dimension == 1) { 383 generate_new_array(v->type, c->statements, v, 384 stubClass->transact_data); 385 } 386 else { 387 fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, 388 __LINE__); 389 } 390 } 391 392 realCall->arguments.push_back(v); 393 394 arg = arg->next; 395 } 396 397 // the real call 398 Variable* _result = NULL; 399 if (0 == strcmp(method->type.type.data, "void")) { 400 c->statements->Add(realCall); 401 402 if (!oneway) { 403 // report that there were no exceptions 404 MethodCall* ex = new MethodCall(stubClass->transact_reply, 405 "writeNoException", 0); 406 c->statements->Add(ex); 407 } 408 } else { 409 _result = new Variable(decl->returnType, "_result", 410 decl->returnTypeDimension); 411 c->statements->Add(new VariableDeclaration(_result, realCall)); 412 413 if (!oneway) { 414 // report that there were no exceptions 415 MethodCall* ex = new MethodCall(stubClass->transact_reply, 416 "writeNoException", 0); 417 c->statements->Add(ex); 418 } 419 420 // marshall the return value 421 generate_write_to_parcel(decl->returnType, c->statements, _result, 422 stubClass->transact_reply, 423 Type::PARCELABLE_WRITE_RETURN_VALUE); 424 } 425 426 // out parameters 427 i = 0; 428 arg = method->args; 429 while (arg != NULL) { 430 Type* t = NAMES.Search(arg->type.type.data); 431 Variable* v = stubArgs.Get(i++); 432 433 if (convert_direction(arg->direction.data) & OUT_PARAMETER) { 434 generate_write_to_parcel(t, c->statements, v, 435 stubClass->transact_reply, 436 Type::PARCELABLE_WRITE_RETURN_VALUE); 437 hasOutParams = true; 438 } 439 440 arg = arg->next; 441 } 442 443 // return true 444 c->statements->Add(new ReturnStatement(TRUE_VALUE)); 445 stubClass->transact_switch->cases.push_back(c); 446 447 // == the proxy method =================================================== 448 Method* proxy = new Method; 449 proxy->comment = gather_comments(method->comments_token->extra); 450 proxy->modifiers = PUBLIC; 451 proxy->returnType = NAMES.Search(method->type.type.data); 452 proxy->returnTypeDimension = method->type.dimension; 453 proxy->name = method->name.data; 454 proxy->statements = new StatementBlock; 455 arg = method->args; 456 while (arg != NULL) { 457 proxy->parameters.push_back(new Variable( 458 NAMES.Search(arg->type.type.data), arg->name.data, 459 arg->type.dimension)); 460 arg = arg->next; 461 } 462 proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE); 463 proxyClass->elements.push_back(proxy); 464 465 // the parcels 466 Variable* _data = new Variable(PARCEL_TYPE, "_data"); 467 proxy->statements->Add(new VariableDeclaration(_data, 468 new MethodCall(PARCEL_TYPE, "obtain"))); 469 Variable* _reply = NULL; 470 if (!oneway) { 471 _reply = new Variable(PARCEL_TYPE, "_reply"); 472 proxy->statements->Add(new VariableDeclaration(_reply, 473 new MethodCall(PARCEL_TYPE, "obtain"))); 474 } 475 476 // the return value 477 _result = NULL; 478 if (0 != strcmp(method->type.type.data, "void")) { 479 _result = new Variable(proxy->returnType, "_result", 480 method->type.dimension); 481 proxy->statements->Add(new VariableDeclaration(_result)); 482 } 483 484 // try and finally 485 TryStatement* tryStatement = new TryStatement(); 486 proxy->statements->Add(tryStatement); 487 FinallyStatement* finallyStatement = new FinallyStatement(); 488 proxy->statements->Add(finallyStatement); 489 490 // the interface identifier token: the DESCRIPTOR constant, marshalled as a string 491 tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken", 492 1, new LiteralExpression("DESCRIPTOR"))); 493 494 // the parameters 495 arg = method->args; 496 while (arg != NULL) { 497 Type* t = NAMES.Search(arg->type.type.data); 498 Variable* v = new Variable(t, arg->name.data, arg->type.dimension); 499 int dir = convert_direction(arg->direction.data); 500 if (dir == OUT_PARAMETER && arg->type.dimension != 0) { 501 IfStatement* checklen = new IfStatement(); 502 checklen->expression = new Comparison(v, "==", NULL_VALUE); 503 checklen->statements->Add(new MethodCall(_data, "writeInt", 1, 504 new LiteralExpression("-1"))); 505 checklen->elseif = new IfStatement(); 506 checklen->elseif->statements->Add(new MethodCall(_data, "writeInt", 507 1, new FieldVariable(v, "length"))); 508 tryStatement->statements->Add(checklen); 509 } 510 else if (dir & IN_PARAMETER) { 511 generate_write_to_parcel(t, tryStatement->statements, v, _data, 0); 512 } 513 arg = arg->next; 514 } 515 516 // the transact call 517 MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4, 518 new LiteralExpression("Stub." + transactCodeName), 519 _data, _reply ? _reply : NULL_VALUE, 520 new LiteralExpression( 521 oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0")); 522 tryStatement->statements->Add(call); 523 524 // throw back exceptions. 525 if (_reply) { 526 MethodCall* ex = new MethodCall(_reply, "readException", 0); 527 tryStatement->statements->Add(ex); 528 } 529 530 // returning and cleanup 531 if (_reply != NULL) { 532 if (_result != NULL) { 533 generate_create_from_parcel(proxy->returnType, 534 tryStatement->statements, _result, _reply); 535 } 536 537 // the out/inout parameters 538 arg = method->args; 539 while (arg != NULL) { 540 Type* t = NAMES.Search(arg->type.type.data); 541 Variable* v = new Variable(t, arg->name.data, arg->type.dimension); 542 if (convert_direction(arg->direction.data) & OUT_PARAMETER) { 543 generate_read_from_parcel(t, tryStatement->statements, 544 v, _reply); 545 } 546 arg = arg->next; 547 } 548 549 finallyStatement->statements->Add(new MethodCall(_reply, "recycle")); 550 } 551 finallyStatement->statements->Add(new MethodCall(_data, "recycle")); 552 553 if (_result != NULL) { 554 proxy->statements->Add(new ReturnStatement(_result)); 555 } 556} 557 558static void 559generate_interface_descriptors(StubClass* stub, ProxyClass* proxy) 560{ 561 // the interface descriptor transaction handler 562 Case* c = new Case("INTERFACE_TRANSACTION"); 563 c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 564 1, new LiteralExpression("DESCRIPTOR"))); 565 c->statements->Add(new ReturnStatement(TRUE_VALUE)); 566 stub->transact_switch->cases.push_back(c); 567 568 // and the proxy-side method returning the descriptor directly 569 Method* getDesc = new Method; 570 getDesc->modifiers = PUBLIC; 571 getDesc->returnType = STRING_TYPE; 572 getDesc->returnTypeDimension = 0; 573 getDesc->name = "getInterfaceDescriptor"; 574 getDesc->statements = new StatementBlock; 575 getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); 576 proxy->elements.push_back(getDesc); 577} 578 579static Class* 580generate_interface_class(const interface_type* iface) 581{ 582 InterfaceType* interfaceType = static_cast<InterfaceType*>( 583 NAMES.Find(iface->package, iface->name.data)); 584 585 // the interface class 586 Class* interface = new Class; 587 interface->comment = gather_comments(iface->comments_token->extra); 588 interface->modifiers = PUBLIC; 589 interface->what = Class::INTERFACE; 590 interface->type = interfaceType; 591 interface->interfaces.push_back(IINTERFACE_TYPE); 592 593 // the stub inner class 594 StubClass* stub = new StubClass( 595 NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()), 596 interfaceType); 597 interface->elements.push_back(stub); 598 599 // the proxy inner class 600 ProxyClass* proxy = new ProxyClass( 601 NAMES.Find(iface->package, 602 append(iface->name.data, ".Stub.Proxy").c_str()), 603 interfaceType); 604 stub->elements.push_back(proxy); 605 606 // stub and proxy support for getInterfaceDescriptor() 607 generate_interface_descriptors(stub, proxy); 608 609 // all the declared methods of the interface 610 int index = 0; 611 interface_item_type* item = iface->interface_items; 612 while (item != NULL) { 613 if (item->item_type == METHOD_TYPE) { 614 generate_method((method_type*)item, interface, stub, proxy, index); 615 } 616 item = item->next; 617 index++; 618 } 619 620 return interface; 621} 622 623int 624generate_java(const string& filename, const string& originalSrc, 625 interface_type* iface) 626{ 627 Document* document = new Document; 628 document->comment = ""; 629 if (iface->package) document->package = iface->package; 630 document->originalSrc = originalSrc; 631 document->classes.push_back(generate_interface_class(iface)); 632 633// printf("outputting... filename=%s\n", filename.c_str()); 634 FILE* to; 635 if (filename == "-") { 636 to = stdout; 637 } else { 638 /* open file in binary mode to ensure that the tool produces the 639 * same output on all platforms !! 640 */ 641 to = fopen(filename.c_str(), "wb"); 642 if (to == NULL) { 643 fprintf(stderr, "unable to open %s for write\n", filename.c_str()); 644 return 1; 645 } 646 } 647 648 document->Write(to); 649 650 fclose(to); 651 return 0; 652} 653 654