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