blob: e3c0af0e8938cc728385095e6cda8d04cf2ab796 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#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;
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