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