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