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