1 /*
2 * Copyright (C) 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "generate_java.h"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <algorithm>
24 #include <unordered_set>
25
26 #include <android-base/macros.h>
27 #include <android-base/stringprintf.h>
28
29 #include "options.h"
30 #include "type_java.h"
31
32 using std::string;
33
34 using android::base::StringPrintf;
35
36 namespace android {
37 namespace aidl {
38 namespace java {
39
40 // =================================================
41 class StubClass : public Class {
42 public:
43 StubClass(const Type* type, const InterfaceType* interfaceType,
44 JavaTypeNamespace* types);
45 virtual ~StubClass() = default;
46
47 Variable* transact_code;
48 Variable* transact_data;
49 Variable* transact_reply;
50 Variable* transact_flags;
51 SwitchStatement* transact_switch;
52 StatementBlock* transact_statements;
53
54 // Where onTransact cases should be generated as separate methods.
55 bool transact_outline;
56 // Specific methods that should be outlined when transact_outline is true.
57 std::unordered_set<const AidlMethod*> outline_methods;
58 // Number of all methods.
59 size_t all_method_count;
60
61 // Finish generation. This will add a default case to the switch.
62 void finish();
63
64 Expression* get_transact_descriptor(const JavaTypeNamespace* types,
65 const AidlMethod* method);
66
67 private:
68 void make_as_interface(const InterfaceType* interfaceType,
69 JavaTypeNamespace* types);
70
71 Variable* transact_descriptor;
72
73 DISALLOW_COPY_AND_ASSIGN(StubClass);
74 };
75
StubClass(const Type * type,const InterfaceType * interfaceType,JavaTypeNamespace * types)76 StubClass::StubClass(const Type* type, const InterfaceType* interfaceType,
77 JavaTypeNamespace* types)
78 : Class() {
79 transact_descriptor = nullptr;
80 transact_outline = false;
81 all_method_count = 0; // Will be set when outlining may be enabled.
82
83 this->comment = "/** Local-side IPC implementation stub class. */";
84 this->modifiers = PUBLIC | ABSTRACT | STATIC;
85 this->what = Class::CLASS;
86 this->type = type;
87 this->extends = types->BinderNativeType();
88 this->interfaces.push_back(interfaceType);
89
90 // descriptor
91 Field* descriptor =
92 new Field(STATIC | FINAL | PRIVATE,
93 new Variable(types->StringType(), "DESCRIPTOR"));
94 descriptor->value = "\"" + interfaceType->JavaType() + "\"";
95 this->elements.push_back(descriptor);
96
97 // ctor
98 Method* ctor = new Method;
99 ctor->modifiers = PUBLIC;
100 ctor->comment =
101 "/** Construct the stub at attach it to the "
102 "interface. */";
103 ctor->name = "Stub";
104 ctor->statements = new StatementBlock;
105 MethodCall* attach =
106 new MethodCall(THIS_VALUE, "attachInterface", 2, THIS_VALUE,
107 new LiteralExpression("DESCRIPTOR"));
108 ctor->statements->Add(attach);
109 this->elements.push_back(ctor);
110
111 // asInterface
112 make_as_interface(interfaceType, types);
113
114 // asBinder
115 Method* asBinder = new Method;
116 asBinder->modifiers = PUBLIC | OVERRIDE;
117 asBinder->returnType = types->IBinderType();
118 asBinder->name = "asBinder";
119 asBinder->statements = new StatementBlock;
120 asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
121 this->elements.push_back(asBinder);
122
123 // onTransact
124 this->transact_code = new Variable(types->IntType(), "code");
125 this->transact_data = new Variable(types->ParcelType(), "data");
126 this->transact_reply = new Variable(types->ParcelType(), "reply");
127 this->transact_flags = new Variable(types->IntType(), "flags");
128 Method* onTransact = new Method;
129 onTransact->modifiers = PUBLIC | OVERRIDE;
130 onTransact->returnType = types->BoolType();
131 onTransact->name = "onTransact";
132 onTransact->parameters.push_back(this->transact_code);
133 onTransact->parameters.push_back(this->transact_data);
134 onTransact->parameters.push_back(this->transact_reply);
135 onTransact->parameters.push_back(this->transact_flags);
136 onTransact->statements = new StatementBlock;
137 transact_statements = onTransact->statements;
138 onTransact->exceptions.push_back(types->RemoteExceptionType());
139 this->elements.push_back(onTransact);
140 this->transact_switch = new SwitchStatement(this->transact_code);
141 }
142
finish()143 void StubClass::finish() {
144 Case* default_case = new Case;
145
146 MethodCall* superCall = new MethodCall(
147 SUPER_VALUE, "onTransact", 4, this->transact_code, this->transact_data,
148 this->transact_reply, this->transact_flags);
149 default_case->statements->Add(new ReturnStatement(superCall));
150 transact_switch->cases.push_back(default_case);
151
152 transact_statements->Add(this->transact_switch);
153 }
154
155 // The the expression for the interface's descriptor to be used when
156 // generating code for the given method. Null is acceptable for method
157 // and stands for synthetic cases.
get_transact_descriptor(const JavaTypeNamespace * types,const AidlMethod * method)158 Expression* StubClass::get_transact_descriptor(const JavaTypeNamespace* types,
159 const AidlMethod* method) {
160 if (transact_outline) {
161 if (method != nullptr) {
162 // When outlining, each outlined method needs its own literal.
163 if (outline_methods.count(method) != 0) {
164 return new LiteralExpression("DESCRIPTOR");
165 }
166 } else {
167 // Synthetic case. A small number is assumed. Use its own descriptor
168 // if there are only synthetic cases.
169 if (outline_methods.size() == all_method_count) {
170 return new LiteralExpression("DESCRIPTOR");
171 }
172 }
173 }
174
175 // When not outlining, store the descriptor literal into a local variable, in
176 // an effort to save const-string instructions in each switch case.
177 if (transact_descriptor == nullptr) {
178 transact_descriptor = new Variable(types->StringType(), "descriptor");
179 transact_statements->Add(
180 new VariableDeclaration(transact_descriptor,
181 new LiteralExpression("DESCRIPTOR")));
182 }
183 return transact_descriptor;
184 }
185
make_as_interface(const InterfaceType * interfaceType,JavaTypeNamespace * types)186 void StubClass::make_as_interface(const InterfaceType* interfaceType,
187 JavaTypeNamespace* types) {
188 Variable* obj = new Variable(types->IBinderType(), "obj");
189
190 Method* m = new Method;
191 m->comment = "/**\n * Cast an IBinder object into an ";
192 m->comment += interfaceType->JavaType();
193 m->comment += " interface,\n";
194 m->comment += " * generating a proxy if needed.\n */";
195 m->modifiers = PUBLIC | STATIC;
196 m->returnType = interfaceType;
197 m->name = "asInterface";
198 m->parameters.push_back(obj);
199 m->statements = new StatementBlock;
200
201 IfStatement* ifstatement = new IfStatement();
202 ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
203 ifstatement->statements = new StatementBlock;
204 ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
205 m->statements->Add(ifstatement);
206
207 // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
208 MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
209 queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
210 IInterfaceType* iinType = new IInterfaceType(types);
211 Variable* iin = new Variable(iinType, "iin");
212 VariableDeclaration* iinVd =
213 new VariableDeclaration(iin, queryLocalInterface, NULL);
214 m->statements->Add(iinVd);
215
216 // Ensure the instance type of the local object is as expected.
217 // One scenario where this is needed is if another package (with a
218 // different class loader) runs in the same process as the service.
219
220 // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>)
221 // iin;
222 Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
223 Comparison* instOfCheck =
224 new Comparison(iin, " instanceof ",
225 new LiteralExpression(interfaceType->JavaType()));
226 IfStatement* instOfStatement = new IfStatement();
227 instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
228 instOfStatement->statements = new StatementBlock;
229 instOfStatement->statements->Add(
230 new ReturnStatement(new Cast(interfaceType, iin)));
231 m->statements->Add(instOfStatement);
232
233 NewExpression* ne = new NewExpression(interfaceType->GetProxy());
234 ne->arguments.push_back(obj);
235 m->statements->Add(new ReturnStatement(ne));
236
237 this->elements.push_back(m);
238 }
239
240 // =================================================
241 class ProxyClass : public Class {
242 public:
243 ProxyClass(const JavaTypeNamespace* types, const Type* type,
244 const InterfaceType* interfaceType);
245 virtual ~ProxyClass();
246
247 Variable* mRemote;
248 bool mOneWay;
249 };
250
ProxyClass(const JavaTypeNamespace * types,const Type * type,const InterfaceType * interfaceType)251 ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type,
252 const InterfaceType* interfaceType)
253 : Class() {
254 this->modifiers = PRIVATE | STATIC;
255 this->what = Class::CLASS;
256 this->type = type;
257 this->interfaces.push_back(interfaceType);
258
259 mOneWay = interfaceType->OneWay();
260
261 // IBinder mRemote
262 mRemote = new Variable(types->IBinderType(), "mRemote");
263 this->elements.push_back(new Field(PRIVATE, mRemote));
264
265 // Proxy()
266 Variable* remote = new Variable(types->IBinderType(), "remote");
267 Method* ctor = new Method;
268 ctor->name = "Proxy";
269 ctor->statements = new StatementBlock;
270 ctor->parameters.push_back(remote);
271 ctor->statements->Add(new Assignment(mRemote, remote));
272 this->elements.push_back(ctor);
273
274 // IBinder asBinder()
275 Method* asBinder = new Method;
276 asBinder->modifiers = PUBLIC | OVERRIDE;
277 asBinder->returnType = types->IBinderType();
278 asBinder->name = "asBinder";
279 asBinder->statements = new StatementBlock;
280 asBinder->statements->Add(new ReturnStatement(mRemote));
281 this->elements.push_back(asBinder);
282 }
283
~ProxyClass()284 ProxyClass::~ProxyClass() {}
285
286 // =================================================
generate_new_array(const Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,JavaTypeNamespace * types)287 static void generate_new_array(const Type* t, StatementBlock* addTo,
288 Variable* v, Variable* parcel,
289 JavaTypeNamespace* types) {
290 Variable* len = new Variable(types->IntType(), v->name + "_length");
291 addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
292 IfStatement* lencheck = new IfStatement();
293 lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
294 lencheck->statements->Add(new Assignment(v, NULL_VALUE));
295 lencheck->elseif = new IfStatement();
296 lencheck->elseif->statements->Add(
297 new Assignment(v, new NewArrayExpression(t, len)));
298 addTo->Add(lencheck);
299 }
300
generate_write_to_parcel(const Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,int flags)301 static void generate_write_to_parcel(const Type* t, StatementBlock* addTo,
302 Variable* v, Variable* parcel, int flags) {
303 t->WriteToParcel(addTo, v, parcel, flags);
304 }
305
generate_create_from_parcel(const Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,Variable ** cl)306 static void generate_create_from_parcel(const Type* t, StatementBlock* addTo,
307 Variable* v, Variable* parcel,
308 Variable** cl) {
309 t->CreateFromParcel(addTo, v, parcel, cl);
310 }
311
generate_int_constant(const AidlIntConstant & constant,Class * interface)312 static void generate_int_constant(const AidlIntConstant& constant,
313 Class* interface) {
314 IntConstant* decl = new IntConstant(constant.GetName(), constant.GetValue());
315 interface->elements.push_back(decl);
316 }
317
generate_string_constant(const AidlStringConstant & constant,Class * interface)318 static void generate_string_constant(const AidlStringConstant& constant,
319 Class* interface) {
320 StringConstant* decl = new StringConstant(constant.GetName(),
321 constant.GetValue());
322 interface->elements.push_back(decl);
323 }
324
generate_interface_method(const AidlMethod & method,JavaTypeNamespace * types)325 static std::unique_ptr<Method> generate_interface_method(
326 const AidlMethod& method, JavaTypeNamespace* types) {
327 std::unique_ptr<Method> decl(new Method);
328 decl->comment = method.GetComments();
329 decl->modifiers = PUBLIC;
330 decl->returnType = method.GetType().GetLanguageType<Type>();
331 decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
332 decl->name = method.GetName();
333
334 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
335 decl->parameters.push_back(
336 new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
337 arg->GetType().IsArray() ? 1 : 0));
338 }
339
340 decl->exceptions.push_back(types->RemoteExceptionType());
341
342 return decl;
343 }
344
generate_stub_code(const AidlInterface & iface,const AidlMethod & method,const std::string & transactCodeName,bool oneway,Variable * transact_data,Variable * transact_reply,JavaTypeNamespace * types,StatementBlock * statements,StubClass * stubClass)345 static void generate_stub_code(const AidlInterface& iface,
346 const AidlMethod& method,
347 const std::string& transactCodeName,
348 bool oneway,
349 Variable* transact_data,
350 Variable* transact_reply,
351 JavaTypeNamespace* types,
352 StatementBlock* statements,
353 StubClass* stubClass) {
354 TryStatement* tryStatement = nullptr;
355 FinallyStatement* finallyStatement = nullptr;
356 MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName());
357
358 // interface token validation is the very first thing we do
359 statements->Add(new MethodCall(transact_data,
360 "enforceInterface", 1,
361 stubClass->get_transact_descriptor(types,
362 &method)));
363
364 // args
365 VariableFactory stubArgs("_arg");
366 {
367 Variable* cl = NULL;
368 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
369 const Type* t = arg->GetType().GetLanguageType<Type>();
370 Variable* v = stubArgs.Get(t);
371 v->dimension = arg->GetType().IsArray() ? 1 : 0;
372
373 statements->Add(new VariableDeclaration(v));
374
375 if (arg->GetDirection() & AidlArgument::IN_DIR) {
376 generate_create_from_parcel(t,
377 statements,
378 v,
379 transact_data,
380 &cl);
381 } else {
382 if (!arg->GetType().IsArray()) {
383 statements->Add(new Assignment(v, new NewExpression(v->type)));
384 } else {
385 generate_new_array(v->type,
386 statements,
387 v,
388 transact_data,
389 types);
390 }
391 }
392
393 realCall->arguments.push_back(v);
394 }
395 }
396
397 if (iface.ShouldGenerateTraces()) {
398 // try and finally, but only when generating trace code
399 tryStatement = new TryStatement();
400 finallyStatement = new FinallyStatement();
401
402 tryStatement->statements->Add(new MethodCall(
403 new LiteralExpression("android.os.Trace"), "traceBegin", 2,
404 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
405 new StringLiteralExpression(iface.GetName() + "::"
406 + method.GetName() + "::server")));
407
408 finallyStatement->statements->Add(new MethodCall(
409 new LiteralExpression("android.os.Trace"), "traceEnd", 1,
410 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
411 }
412
413 // the real call
414 if (method.GetType().GetName() == "void") {
415 if (iface.ShouldGenerateTraces()) {
416 statements->Add(tryStatement);
417 tryStatement->statements->Add(realCall);
418 statements->Add(finallyStatement);
419 } else {
420 statements->Add(realCall);
421 }
422
423 if (!oneway) {
424 // report that there were no exceptions
425 MethodCall* ex =
426 new MethodCall(transact_reply, "writeNoException", 0);
427 statements->Add(ex);
428 }
429 } else {
430 Variable* _result =
431 new Variable(method.GetType().GetLanguageType<Type>(),
432 "_result",
433 method.GetType().IsArray() ? 1 : 0);
434 if (iface.ShouldGenerateTraces()) {
435 statements->Add(new VariableDeclaration(_result));
436 statements->Add(tryStatement);
437 tryStatement->statements->Add(new Assignment(_result, realCall));
438 statements->Add(finallyStatement);
439 } else {
440 statements->Add(new VariableDeclaration(_result, realCall));
441 }
442
443 if (!oneway) {
444 // report that there were no exceptions
445 MethodCall* ex =
446 new MethodCall(transact_reply, "writeNoException", 0);
447 statements->Add(ex);
448 }
449
450 // marshall the return value
451 generate_write_to_parcel(method.GetType().GetLanguageType<Type>(),
452 statements,
453 _result,
454 transact_reply,
455 Type::PARCELABLE_WRITE_RETURN_VALUE);
456 }
457
458 // out parameters
459 int i = 0;
460 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
461 const Type* t = arg->GetType().GetLanguageType<Type>();
462 Variable* v = stubArgs.Get(i++);
463
464 if (arg->GetDirection() & AidlArgument::OUT_DIR) {
465 generate_write_to_parcel(t,
466 statements,
467 v,
468 transact_reply,
469 Type::PARCELABLE_WRITE_RETURN_VALUE);
470 }
471 }
472
473 // return true
474 statements->Add(new ReturnStatement(TRUE_VALUE));
475 }
476
477
generate_stub_case(const AidlInterface & iface,const AidlMethod & method,const std::string & transactCodeName,bool oneway,StubClass * stubClass,JavaTypeNamespace * types)478 static void generate_stub_case(const AidlInterface& iface,
479 const AidlMethod& method,
480 const std::string& transactCodeName,
481 bool oneway,
482 StubClass* stubClass,
483 JavaTypeNamespace* types) {
484 Case* c = new Case(transactCodeName);
485
486 generate_stub_code(iface,
487 method,
488 transactCodeName,
489 oneway,
490 stubClass->transact_data,
491 stubClass->transact_reply,
492 types,
493 c->statements,
494 stubClass);
495
496 stubClass->transact_switch->cases.push_back(c);
497 }
498
generate_stub_case_outline(const AidlInterface & iface,const AidlMethod & method,const std::string & transactCodeName,bool oneway,StubClass * stubClass,JavaTypeNamespace * types)499 static void generate_stub_case_outline(const AidlInterface& iface,
500 const AidlMethod& method,
501 const std::string& transactCodeName,
502 bool oneway,
503 StubClass* stubClass,
504 JavaTypeNamespace* types) {
505 std::string outline_name = "onTransact$" + method.GetName() + "$";
506 // Generate an "outlined" method with the actual code.
507 {
508 Variable* transact_data = new Variable(types->ParcelType(), "data");
509 Variable* transact_reply = new Variable(types->ParcelType(), "reply");
510 Method* onTransact_case = new Method;
511 onTransact_case->modifiers = PRIVATE;
512 onTransact_case->returnType = types->BoolType();
513 onTransact_case->name = outline_name;
514 onTransact_case->parameters.push_back(transact_data);
515 onTransact_case->parameters.push_back(transact_reply);
516 onTransact_case->statements = new StatementBlock;
517 onTransact_case->exceptions.push_back(types->RemoteExceptionType());
518 stubClass->elements.push_back(onTransact_case);
519
520 generate_stub_code(iface,
521 method,
522 transactCodeName,
523 oneway,
524 transact_data,
525 transact_reply,
526 types,
527 onTransact_case->statements,
528 stubClass);
529 }
530
531 // Generate the case dispatch.
532 {
533 Case* c = new Case(transactCodeName);
534
535 MethodCall* helper_call = new MethodCall(THIS_VALUE,
536 outline_name,
537 2,
538 stubClass->transact_data,
539 stubClass->transact_reply);
540 c->statements->Add(new ReturnStatement(helper_call));
541
542 stubClass->transact_switch->cases.push_back(c);
543 }
544 }
545
generate_proxy_method(const AidlInterface & iface,const AidlMethod & method,const std::string & transactCodeName,bool oneway,ProxyClass * proxyClass,JavaTypeNamespace * types)546 static std::unique_ptr<Method> generate_proxy_method(
547 const AidlInterface& iface,
548 const AidlMethod& method,
549 const std::string& transactCodeName,
550 bool oneway,
551 ProxyClass* proxyClass,
552 JavaTypeNamespace* types) {
553 std::unique_ptr<Method> proxy(new Method);
554 proxy->comment = method.GetComments();
555 proxy->modifiers = PUBLIC | OVERRIDE;
556 proxy->returnType = method.GetType().GetLanguageType<Type>();
557 proxy->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
558 proxy->name = method.GetName();
559 proxy->statements = new StatementBlock;
560 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
561 proxy->parameters.push_back(
562 new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
563 arg->GetType().IsArray() ? 1 : 0));
564 }
565 proxy->exceptions.push_back(types->RemoteExceptionType());
566
567 // the parcels
568 Variable* _data = new Variable(types->ParcelType(), "_data");
569 proxy->statements->Add(new VariableDeclaration(
570 _data, new MethodCall(types->ParcelType(), "obtain")));
571 Variable* _reply = NULL;
572 if (!oneway) {
573 _reply = new Variable(types->ParcelType(), "_reply");
574 proxy->statements->Add(new VariableDeclaration(
575 _reply, new MethodCall(types->ParcelType(), "obtain")));
576 }
577
578 // the return value
579 Variable* _result = NULL;
580 if (method.GetType().GetName() != "void") {
581 _result = new Variable(proxy->returnType, "_result",
582 method.GetType().IsArray() ? 1 : 0);
583 proxy->statements->Add(new VariableDeclaration(_result));
584 }
585
586 // try and finally
587 TryStatement* tryStatement = new TryStatement();
588 proxy->statements->Add(tryStatement);
589 FinallyStatement* finallyStatement = new FinallyStatement();
590 proxy->statements->Add(finallyStatement);
591
592 if (iface.ShouldGenerateTraces()) {
593 tryStatement->statements->Add(new MethodCall(
594 new LiteralExpression("android.os.Trace"), "traceBegin", 2,
595 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
596 new StringLiteralExpression(iface.GetName() + "::" +
597 method.GetName() + "::client")));
598 }
599
600 // the interface identifier token: the DESCRIPTOR constant, marshalled as a
601 // string
602 tryStatement->statements->Add(new MethodCall(
603 _data, "writeInterfaceToken", 1, new LiteralExpression("DESCRIPTOR")));
604
605 // the parameters
606 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
607 const Type* t = arg->GetType().GetLanguageType<Type>();
608 Variable* v =
609 new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
610 AidlArgument::Direction dir = arg->GetDirection();
611 if (dir == AidlArgument::OUT_DIR && arg->GetType().IsArray()) {
612 IfStatement* checklen = new IfStatement();
613 checklen->expression = new Comparison(v, "==", NULL_VALUE);
614 checklen->statements->Add(
615 new MethodCall(_data, "writeInt", 1, new LiteralExpression("-1")));
616 checklen->elseif = new IfStatement();
617 checklen->elseif->statements->Add(
618 new MethodCall(_data, "writeInt", 1, new FieldVariable(v, "length")));
619 tryStatement->statements->Add(checklen);
620 } else if (dir & AidlArgument::IN_DIR) {
621 generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
622 } else {
623 delete v;
624 }
625 }
626
627 // the transact call
628 MethodCall* call = new MethodCall(
629 proxyClass->mRemote, "transact", 4,
630 new LiteralExpression("Stub." + transactCodeName), _data,
631 _reply ? _reply : NULL_VALUE,
632 new LiteralExpression(oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
633 tryStatement->statements->Add(call);
634
635 // throw back exceptions.
636 if (_reply) {
637 MethodCall* ex = new MethodCall(_reply, "readException", 0);
638 tryStatement->statements->Add(ex);
639 }
640
641 // returning and cleanup
642 if (_reply != NULL) {
643 Variable* cl = nullptr;
644 if (_result != NULL) {
645 generate_create_from_parcel(proxy->returnType, tryStatement->statements,
646 _result, _reply, &cl);
647 }
648
649 // the out/inout parameters
650 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
651 const Type* t = arg->GetType().GetLanguageType<Type>();
652 if (arg->GetDirection() & AidlArgument::OUT_DIR) {
653 Variable* v =
654 new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
655 t->ReadFromParcel(tryStatement->statements, v, _reply, &cl);
656 }
657 }
658
659 finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
660 }
661 finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
662
663 if (iface.ShouldGenerateTraces()) {
664 finallyStatement->statements->Add(new MethodCall(
665 new LiteralExpression("android.os.Trace"), "traceEnd", 1,
666 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
667 }
668
669 if (_result != NULL) {
670 proxy->statements->Add(new ReturnStatement(_result));
671 }
672
673 return proxy;
674 }
675
generate_methods(const AidlInterface & iface,const AidlMethod & method,Class * interface,StubClass * stubClass,ProxyClass * proxyClass,int index,JavaTypeNamespace * types)676 static void generate_methods(const AidlInterface& iface,
677 const AidlMethod& method,
678 Class* interface,
679 StubClass* stubClass,
680 ProxyClass* proxyClass,
681 int index,
682 JavaTypeNamespace* types) {
683 const bool oneway = proxyClass->mOneWay || method.IsOneway();
684
685 // == the TRANSACT_ constant =============================================
686 string transactCodeName = "TRANSACTION_";
687 transactCodeName += method.GetName();
688
689 Field* transactCode = new Field(
690 STATIC | FINAL, new Variable(types->IntType(), transactCodeName));
691 transactCode->value =
692 StringPrintf("(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
693 stubClass->elements.push_back(transactCode);
694
695 // == the declaration in the interface ===================================
696 Method* decl = generate_interface_method(method, types).release();
697 interface->elements.push_back(decl);
698
699 // == the stub method ====================================================
700 bool outline_stub = stubClass->transact_outline &&
701 stubClass->outline_methods.count(&method) != 0;
702 if (outline_stub) {
703 generate_stub_case_outline(iface,
704 method,
705 transactCodeName,
706 oneway,
707 stubClass,
708 types);
709 } else {
710 generate_stub_case(iface, method, transactCodeName, oneway, stubClass, types);
711 }
712
713 // == the proxy method ===================================================
714 Method* proxy = generate_proxy_method(iface,
715 method,
716 transactCodeName,
717 oneway,
718 proxyClass,
719 types).release();
720 proxyClass->elements.push_back(proxy);
721 }
722
generate_interface_descriptors(StubClass * stub,ProxyClass * proxy,const JavaTypeNamespace * types)723 static void generate_interface_descriptors(StubClass* stub, ProxyClass* proxy,
724 const JavaTypeNamespace* types) {
725 // the interface descriptor transaction handler
726 Case* c = new Case("INTERFACE_TRANSACTION");
727 c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 1,
728 stub->get_transact_descriptor(types,
729 nullptr)));
730 c->statements->Add(new ReturnStatement(TRUE_VALUE));
731 stub->transact_switch->cases.push_back(c);
732
733 // and the proxy-side method returning the descriptor directly
734 Method* getDesc = new Method;
735 getDesc->modifiers = PUBLIC;
736 getDesc->returnType = types->StringType();
737 getDesc->returnTypeDimension = 0;
738 getDesc->name = "getInterfaceDescriptor";
739 getDesc->statements = new StatementBlock;
740 getDesc->statements->Add(
741 new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
742 proxy->elements.push_back(getDesc);
743 }
744
745 // Check whether (some) methods in this interface should be "outlined," that
746 // is, have specific onTransact methods for certain cases. Set up StubClass
747 // metadata accordingly.
748 //
749 // Outlining will be enabled if the interface has more than outline_threshold
750 // methods. In that case, the methods are sorted by number of arguments
751 // (so that more "complex" methods come later), and the first non_outline_count
752 // number of methods not outlined (are kept in the onTransact() method).
753 //
754 // Requirements: non_outline_count <= outline_threshold.
compute_outline_methods(const AidlInterface * iface,StubClass * stub,size_t outline_threshold,size_t non_outline_count)755 static void compute_outline_methods(const AidlInterface* iface,
756 StubClass* stub,
757 size_t outline_threshold,
758 size_t non_outline_count) {
759 CHECK_LE(non_outline_count, outline_threshold);
760 // We'll outline (create sub methods) if there are more than min_methods
761 // cases.
762 stub->transact_outline = iface->GetMethods().size() > outline_threshold;
763 if (stub->transact_outline) {
764 stub->all_method_count = iface->GetMethods().size();
765 std::vector<const AidlMethod*> methods;
766 methods.reserve(iface->GetMethods().size());
767 for (const std::unique_ptr<AidlMethod>& ptr : iface->GetMethods()) {
768 methods.push_back(ptr.get());
769 }
770
771 std::stable_sort(
772 methods.begin(),
773 methods.end(),
774 [](const AidlMethod* m1, const AidlMethod* m2) {
775 return m1->GetArguments().size() < m2->GetArguments().size();
776 });
777
778 stub->outline_methods.insert(methods.begin() + non_outline_count,
779 methods.end());
780 }
781 }
782
generate_binder_interface_class(const AidlInterface * iface,JavaTypeNamespace * types,const JavaOptions & options)783 Class* generate_binder_interface_class(const AidlInterface* iface,
784 JavaTypeNamespace* types,
785 const JavaOptions& options) {
786 const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
787
788 // the interface class
789 Class* interface = new Class;
790 interface->comment = iface->GetComments();
791 interface->modifiers = PUBLIC;
792 interface->what = Class::INTERFACE;
793 interface->type = interfaceType;
794 interface->interfaces.push_back(types->IInterfaceType());
795
796 // the stub inner class
797 StubClass* stub =
798 new StubClass(interfaceType->GetStub(), interfaceType, types);
799 interface->elements.push_back(stub);
800
801 compute_outline_methods(iface,
802 stub,
803 options.onTransact_outline_threshold_,
804 options.onTransact_non_outline_count_);
805
806 // the proxy inner class
807 ProxyClass* proxy =
808 new ProxyClass(types, interfaceType->GetProxy(), interfaceType);
809 stub->elements.push_back(proxy);
810
811 // stub and proxy support for getInterfaceDescriptor()
812 generate_interface_descriptors(stub, proxy, types);
813
814 // all the declared constants of the interface
815 for (const auto& item : iface->GetIntConstants()) {
816 generate_int_constant(*item, interface);
817 }
818 for (const auto& item : iface->GetStringConstants()) {
819 generate_string_constant(*item, interface);
820 }
821
822 // all the declared methods of the interface
823
824 for (const auto& item : iface->GetMethods()) {
825 generate_methods(*iface,
826 *item,
827 interface,
828 stub,
829 proxy,
830 item->GetId(),
831 types);
832 }
833 stub->finish();
834
835 return interface;
836 }
837
838 } // namespace java
839 } // namespace android
840 } // namespace aidl
841