blob: affac0f4558f279aa98a66a093211e84bc588479 [file] [log] [blame]
The Android Open Source Project46c012c2008-10-21 07:00:00 -07001#include "generate_java.h"
2#include "AST.h"
3#include "Type.h"
Alexey Zaytsevccace322008-10-21 23:52:01 +04004#include <string.h>
The Android Open Source Project46c012c2008-10-21 07:00:00 -07005#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