• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // =================================================
10 class VariableFactory
11 {
12 public:
13     VariableFactory(const string& base); // base must be short
14     Variable* Get(Type* type);
15     Variable* Get(int index);
16 private:
17     vector<Variable*> m_vars;
18     string m_base;
19     int m_index;
20 };
21 
VariableFactory(const string & base)22 VariableFactory::VariableFactory(const string& base)
23     :m_base(base),
24      m_index(0)
25 {
26 }
27 
28 Variable*
Get(Type * type)29 VariableFactory::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 
39 Variable*
Get(int index)40 VariableFactory::Get(int index)
41 {
42     return m_vars[index];
43 }
44 
45 // =================================================
46 class StubClass : public Class
47 {
48 public:
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;
57 private:
58     void make_as_interface(Type* interfaceType);
59 };
60 
StubClass(Type * type,Type * interfaceType)61 StubClass::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 
~StubClass()126 StubClass::~StubClass()
127 {
128 }
129 
130 void
make_as_interface(Type * interfaceType)131 StubClass::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 // =================================================
186 class ProxyClass : public Class
187 {
188 public:
189     ProxyClass(Type* type, InterfaceType* interfaceType);
190     virtual ~ProxyClass();
191 
192     Variable* mRemote;
193     bool mOneWay;
194 };
195 
ProxyClass(Type * type,InterfaceType * interfaceType)196 ProxyClass::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 
~ProxyClass()229 ProxyClass::~ProxyClass()
230 {
231 }
232 
233 // =================================================
234 static string
gather_comments(extra_text_type * extra)235 gather_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 
252 static string
append(const char * a,const char * b)253 append(const char* a, const char* b)
254 {
255     string s = a;
256     s += b;
257     return s;
258 }
259 
260 static void
generate_new_array(Type * t,StatementBlock * addTo,Variable * v,Variable * parcel)261 generate_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 
275 static void
generate_write_to_parcel(Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,int flags)276 generate_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 
287 static void
generate_create_from_parcel(Type * t,StatementBlock * addTo,Variable * v,Variable * parcel)288 generate_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 
299 static void
generate_read_from_parcel(Type * t,StatementBlock * addTo,Variable * v,Variable * parcel)300 generate_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 
312 static void
generate_method(const method_type * method,Class * interface,StubClass * stubClass,ProxyClass * proxyClass,int index)313 generate_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 
558 static void
generate_interface_descriptors(StubClass * stub,ProxyClass * proxy)559 generate_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 
579 static Class*
generate_interface_class(const interface_type * iface)580 generate_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 
623 int
generate_java(const string & filename,const string & originalSrc,interface_type * iface)624 generate_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