blob: f291ceb2b09fbbe57acd3950e2543410ba5e8d54 [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001#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// =================================================
9class StubClass : public Class
10{
11public:
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;
20private:
21 void make_as_interface(Type* interfaceType);
22};
23
24StubClass::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
89StubClass::~StubClass()
90{
91}
92
93void
94StubClass::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// =================================================
149class ProxyClass : public Class
150{
151public:
152 ProxyClass(Type* type, InterfaceType* interfaceType);
153 virtual ~ProxyClass();
154
155 Variable* mRemote;
156 bool mOneWay;
157};
158
159ProxyClass::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
192ProxyClass::~ProxyClass()
193{
194}
195
196// =================================================
197static void
198generate_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
212static void
213generate_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
224static void
225generate_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
236static void
237generate_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
249static void
250generate_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
495static void
496generate_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
516Class*
517generate_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