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 "aidl.h"
18 #include "aidl_to_java.h"
19 #include "generate_java.h"
20 #include "options.h"
21 #include "type_java.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <algorithm>
28 #include <unordered_set>
29 #include <utility>
30 #include <vector>
31
32 #include <android-base/macros.h>
33 #include <android-base/stringprintf.h>
34
35 using android::base::Join;
36 using android::base::StringPrintf;
37
38 using std::string;
39 using std::unique_ptr;
40 using std::vector;
41
42 namespace android {
43 namespace aidl {
44 namespace java {
45
46 // =================================================
47 class VariableFactory {
48 public:
49 using Variable = ::android::aidl::java::Variable;
50 using Type = ::android::aidl::java::Type;
51
VariableFactory(const std::string & base)52 explicit VariableFactory(const std::string& base) : base_(base), index_(0) {}
Get(const Type * type)53 Variable* Get(const Type* type) {
54 Variable* v = new Variable(type->JavaType(), StringPrintf("%s%d", base_.c_str(), index_));
55 vars_.push_back(v);
56 index_++;
57 return v;
58 }
59
Get(int index)60 Variable* Get(int index) { return vars_[index]; }
61
62 private:
63 std::vector<Variable*> vars_;
64 std::string base_;
65 int index_;
66
67 DISALLOW_COPY_AND_ASSIGN(VariableFactory);
68 };
69
70 // =================================================
71 class StubClass : public Class {
72 public:
73 StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types,
74 const Options& options);
75 ~StubClass() override = default;
76
77 Variable* transact_code;
78 Variable* transact_data;
79 Variable* transact_reply;
80 Variable* transact_flags;
81 SwitchStatement* transact_switch;
82 StatementBlock* transact_statements;
83 SwitchStatement* code_to_method_name_switch;
84
85 // Where onTransact cases should be generated as separate methods.
86 bool transact_outline;
87 // Specific methods that should be outlined when transact_outline is true.
88 std::unordered_set<const AidlMethod*> outline_methods;
89 // Number of all methods.
90 size_t all_method_count;
91
92 // Finish generation. This will add a default case to the switch.
93 void finish();
94
95 Expression* get_transact_descriptor(const JavaTypeNamespace* types,
96 const AidlMethod* method);
97
98 private:
99 void make_as_interface(const InterfaceType* interfaceType,
100 JavaTypeNamespace* types);
101
102 Variable* transact_descriptor;
103 const Options& options_;
104
105 DISALLOW_COPY_AND_ASSIGN(StubClass);
106 };
107
StubClass(const Type * type,const InterfaceType * interfaceType,JavaTypeNamespace * types,const Options & options)108 StubClass::StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types,
109 const Options& options)
110 : Class(), options_(options) {
111 transact_descriptor = nullptr;
112 transact_outline = false;
113 all_method_count = 0; // Will be set when outlining may be enabled.
114
115 this->comment = "/** Local-side IPC implementation stub class. */";
116 this->modifiers = PUBLIC | ABSTRACT | STATIC;
117 this->what = Class::CLASS;
118 this->type = type->JavaType();
119 this->extends = types->BinderNativeType()->JavaType();
120 this->interfaces.push_back(interfaceType->JavaType());
121
122 // descriptor
123 Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
124 new Variable(types->StringType()->JavaType(), "DESCRIPTOR"));
125 descriptor->value = "\"" + interfaceType->JavaType() + "\"";
126 this->elements.push_back(descriptor);
127
128 // ctor
129 Method* ctor = new Method;
130 ctor->modifiers = PUBLIC;
131 ctor->comment =
132 "/** Construct the stub at attach it to the "
133 "interface. */";
134 ctor->name = "Stub";
135 ctor->statements = new StatementBlock;
136 MethodCall* attach =
137 new MethodCall(THIS_VALUE, "attachInterface", 2, THIS_VALUE,
138 new LiteralExpression("DESCRIPTOR"));
139 ctor->statements->Add(attach);
140 this->elements.push_back(ctor);
141
142 // asInterface
143 make_as_interface(interfaceType, types);
144
145 // asBinder
146 Method* asBinder = new Method;
147 asBinder->modifiers = PUBLIC | OVERRIDE;
148 asBinder->returnType = types->IBinderType()->JavaType();
149 asBinder->name = "asBinder";
150 asBinder->statements = new StatementBlock;
151 asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
152 this->elements.push_back(asBinder);
153
154 if (options_.GenTransactionNames()) {
155 // getDefaultTransactionName
156 Method* getDefaultTransactionName = new Method;
157 getDefaultTransactionName->comment = "/** @hide */";
158 getDefaultTransactionName->modifiers = PUBLIC | STATIC;
159 getDefaultTransactionName->returnType = types->StringType()->JavaType();
160 getDefaultTransactionName->name = "getDefaultTransactionName";
161 Variable* code = new Variable(types->IntType()->JavaType(), "transactionCode");
162 getDefaultTransactionName->parameters.push_back(code);
163 getDefaultTransactionName->statements = new StatementBlock;
164 this->code_to_method_name_switch = new SwitchStatement(code);
165 getDefaultTransactionName->statements->Add(this->code_to_method_name_switch);
166 this->elements.push_back(getDefaultTransactionName);
167
168 // getTransactionName
169 Method* getTransactionName = new Method;
170 getTransactionName->comment = "/** @hide */";
171 getTransactionName->modifiers = PUBLIC;
172 getTransactionName->returnType = types->StringType()->JavaType();
173 getTransactionName->name = "getTransactionName";
174 Variable* code2 = new Variable(types->IntType()->JavaType(), "transactionCode");
175 getTransactionName->parameters.push_back(code2);
176 getTransactionName->statements = new StatementBlock;
177 getTransactionName->statements->Add(
178 new ReturnStatement(new MethodCall(THIS_VALUE, "getDefaultTransactionName", 1, code2)));
179 this->elements.push_back(getTransactionName);
180 }
181
182 // onTransact
183 this->transact_code = new Variable(types->IntType()->JavaType(), "code");
184 this->transact_data = new Variable(types->ParcelType()->JavaType(), "data");
185 this->transact_reply = new Variable(types->ParcelType()->JavaType(), "reply");
186 this->transact_flags = new Variable(types->IntType()->JavaType(), "flags");
187 Method* onTransact = new Method;
188 onTransact->modifiers = PUBLIC | OVERRIDE;
189 onTransact->returnType = types->BoolType()->JavaType();
190 onTransact->name = "onTransact";
191 onTransact->parameters.push_back(this->transact_code);
192 onTransact->parameters.push_back(this->transact_data);
193 onTransact->parameters.push_back(this->transact_reply);
194 onTransact->parameters.push_back(this->transact_flags);
195 onTransact->statements = new StatementBlock;
196 transact_statements = onTransact->statements;
197 onTransact->exceptions.push_back(types->RemoteExceptionType()->JavaType());
198 this->elements.push_back(onTransact);
199 this->transact_switch = new SwitchStatement(this->transact_code);
200 }
201
finish()202 void StubClass::finish() {
203 Case* default_case = new Case;
204
205 MethodCall* superCall = new MethodCall(
206 SUPER_VALUE, "onTransact", 4, this->transact_code, this->transact_data,
207 this->transact_reply, this->transact_flags);
208 default_case->statements->Add(new ReturnStatement(superCall));
209 transact_switch->cases.push_back(default_case);
210
211 transact_statements->Add(this->transact_switch);
212
213 // getTransactionName
214 if (options_.GenTransactionNames()) {
215 // Some transaction codes are common, e.g. INTERFACE_TRANSACTION or DUMP_TRANSACTION.
216 // Common transaction codes will not be resolved to a string by getTransactionName. The method
217 // will return NULL in this case.
218 Case* code_switch_default_case = new Case;
219 code_switch_default_case->statements->Add(new ReturnStatement(NULL_VALUE));
220 this->code_to_method_name_switch->cases.push_back(code_switch_default_case);
221 }
222 }
223
224 // The the expression for the interface's descriptor to be used when
225 // generating code for the given method. Null is acceptable for method
226 // and stands for synthetic cases.
get_transact_descriptor(const JavaTypeNamespace * types,const AidlMethod * method)227 Expression* StubClass::get_transact_descriptor(const JavaTypeNamespace* types,
228 const AidlMethod* method) {
229 if (transact_outline) {
230 if (method != nullptr) {
231 // When outlining, each outlined method needs its own literal.
232 if (outline_methods.count(method) != 0) {
233 return new LiteralExpression("DESCRIPTOR");
234 }
235 } else {
236 // Synthetic case. A small number is assumed. Use its own descriptor
237 // if there are only synthetic cases.
238 if (outline_methods.size() == all_method_count) {
239 return new LiteralExpression("DESCRIPTOR");
240 }
241 }
242 }
243
244 // When not outlining, store the descriptor literal into a local variable, in
245 // an effort to save const-string instructions in each switch case.
246 if (transact_descriptor == nullptr) {
247 transact_descriptor = new Variable(types->StringType()->JavaType(), "descriptor");
248 transact_statements->Add(
249 new VariableDeclaration(transact_descriptor,
250 new LiteralExpression("DESCRIPTOR")));
251 }
252 return transact_descriptor;
253 }
254
make_as_interface(const InterfaceType * interfaceType,JavaTypeNamespace * types)255 void StubClass::make_as_interface(const InterfaceType* interfaceType,
256 JavaTypeNamespace* types) {
257 Variable* obj = new Variable(types->IBinderType()->JavaType(), "obj");
258
259 Method* m = new Method;
260 m->comment = "/**\n * Cast an IBinder object into an ";
261 m->comment += interfaceType->JavaType();
262 m->comment += " interface,\n";
263 m->comment += " * generating a proxy if needed.\n */";
264 m->modifiers = PUBLIC | STATIC;
265 m->returnType = interfaceType->JavaType();
266 m->name = "asInterface";
267 m->parameters.push_back(obj);
268 m->statements = new StatementBlock;
269
270 IfStatement* ifstatement = new IfStatement();
271 ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
272 ifstatement->statements = new StatementBlock;
273 ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
274 m->statements->Add(ifstatement);
275
276 // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
277 MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
278 queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
279 IInterfaceType iinType(types);
280 Variable* iin = new Variable(iinType.JavaType(), "iin");
281 VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface);
282 m->statements->Add(iinVd);
283
284 // Ensure the instance type of the local object is as expected.
285 // One scenario where this is needed is if another package (with a
286 // different class loader) runs in the same process as the service.
287
288 // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>)
289 // iin;
290 Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
291 Comparison* instOfCheck =
292 new Comparison(iin, " instanceof ",
293 new LiteralExpression(interfaceType->JavaType()));
294 IfStatement* instOfStatement = new IfStatement();
295 instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
296 instOfStatement->statements = new StatementBlock;
297 instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType->JavaType(), iin)));
298 m->statements->Add(instOfStatement);
299
300 NewExpression* ne = new NewExpression(interfaceType->GetProxy()->InstantiableName());
301 ne->arguments.push_back(obj);
302 m->statements->Add(new ReturnStatement(ne));
303
304 this->elements.push_back(m);
305 }
306
307 // =================================================
308 class ProxyClass : public Class {
309 public:
310 ProxyClass(const JavaTypeNamespace* types, const Type* type, const InterfaceType* interfaceType,
311 const Options& options);
312 ~ProxyClass() override;
313
314 Variable* mRemote;
315 };
316
ProxyClass(const JavaTypeNamespace * types,const Type * type,const InterfaceType * interfaceType,const Options & options)317 ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type,
318 const InterfaceType* interfaceType, const Options& options)
319 : Class() {
320 this->modifiers = PRIVATE | STATIC;
321 this->what = Class::CLASS;
322 this->type = type->JavaType();
323 this->interfaces.push_back(interfaceType->JavaType());
324
325 // IBinder mRemote
326 mRemote = new Variable(types->IBinderType()->JavaType(), "mRemote");
327 this->elements.push_back(new Field(PRIVATE, mRemote));
328
329 // Proxy()
330 Variable* remote = new Variable(types->IBinderType()->JavaType(), "remote");
331 Method* ctor = new Method;
332 ctor->name = "Proxy";
333 ctor->statements = new StatementBlock;
334 ctor->parameters.push_back(remote);
335 ctor->statements->Add(new Assignment(mRemote, remote));
336 this->elements.push_back(ctor);
337
338 if (options.Version() > 0) {
339 std::ostringstream code;
340 code << "private int mCachedVersion = -1;\n";
341 this->elements.emplace_back(new LiteralClassElement(code.str()));
342 }
343
344 // IBinder asBinder()
345 Method* asBinder = new Method;
346 asBinder->modifiers = PUBLIC | OVERRIDE;
347 asBinder->returnType = types->IBinderType()->JavaType();
348 asBinder->name = "asBinder";
349 asBinder->statements = new StatementBlock;
350 asBinder->statements->Add(new ReturnStatement(mRemote));
351 this->elements.push_back(asBinder);
352 }
353
~ProxyClass()354 ProxyClass::~ProxyClass() {}
355
356 // =================================================
generate_new_array(const Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,JavaTypeNamespace * types)357 static void generate_new_array(const Type* t, StatementBlock* addTo,
358 Variable* v, Variable* parcel,
359 JavaTypeNamespace* types) {
360 Variable* len = new Variable(types->IntType()->JavaType(), v->name + "_length");
361 addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
362 IfStatement* lencheck = new IfStatement();
363 lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
364 lencheck->statements->Add(new Assignment(v, NULL_VALUE));
365 lencheck->elseif = new IfStatement();
366 lencheck->elseif->statements->Add(new Assignment(v, new NewArrayExpression(t->JavaType(), len)));
367 addTo->Add(lencheck);
368 }
369
generate_write_to_parcel(const AidlTypeSpecifier & type,StatementBlock * addTo,Variable * v,Variable * parcel,bool is_return_value,const AidlTypenames & typenames)370 static void generate_write_to_parcel(const AidlTypeSpecifier& type, StatementBlock* addTo,
371 Variable* v, Variable* parcel, bool is_return_value,
372 const AidlTypenames& typenames) {
373 string code;
374 CodeWriterPtr writer = CodeWriter::ForString(&code);
375 CodeGeneratorContext context{
376 .writer = *(writer.get()),
377 .typenames = typenames,
378 .type = type,
379 .var = v->name,
380 .parcel = parcel->name,
381 .is_return_value = is_return_value,
382 };
383 WriteToParcelFor(context);
384 writer->Close();
385 addTo->Add(new LiteralStatement(code));
386 }
387
generate_int_constant(Class * interface,const std::string & name,const std::string & value)388 static void generate_int_constant(Class* interface, const std::string& name,
389 const std::string& value) {
390 auto code = StringPrintf("public static final int %s = %s;\n", name.c_str(), value.c_str());
391 interface->elements.push_back(new LiteralClassElement(code));
392 }
393
generate_string_constant(Class * interface,const std::string & name,const std::string & value)394 static void generate_string_constant(Class* interface, const std::string& name,
395 const std::string& value) {
396 auto code = StringPrintf("public static final String %s = %s;\n", name.c_str(), value.c_str());
397 interface->elements.push_back(new LiteralClassElement(code));
398 }
399
generate_interface_method(const AidlMethod & method,JavaTypeNamespace * types)400 static std::unique_ptr<Method> generate_interface_method(
401 const AidlMethod& method, JavaTypeNamespace* types) {
402 std::unique_ptr<Method> decl(new Method);
403 decl->comment = method.GetComments();
404 decl->modifiers = PUBLIC;
405 decl->returnType = method.GetType().GetLanguageType<Type>()->JavaType();
406 decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
407 decl->name = method.GetName();
408 decl->annotations = generate_java_annotations(method.GetType());
409
410 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
411 decl->parameters.push_back(new Variable(arg->GetType().GetLanguageType<Type>()->JavaType(),
412 arg->GetName(), arg->GetType().IsArray() ? 1 : 0));
413 }
414
415 decl->exceptions.push_back(types->RemoteExceptionType()->JavaType());
416
417 return decl;
418 }
419
generate_stub_code(const AidlInterface & iface,const AidlMethod & method,bool oneway,Variable * transact_data,Variable * transact_reply,JavaTypeNamespace * types,StatementBlock * statements,StubClass * stubClass,const Options & options)420 static void generate_stub_code(const AidlInterface& iface, const AidlMethod& method, bool oneway,
421 Variable* transact_data, Variable* transact_reply,
422 JavaTypeNamespace* types, StatementBlock* statements,
423 StubClass* stubClass, const Options& options) {
424 TryStatement* tryStatement = nullptr;
425 FinallyStatement* finallyStatement = nullptr;
426 MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName());
427
428 // interface token validation is the very first thing we do
429 statements->Add(new MethodCall(transact_data,
430 "enforceInterface", 1,
431 stubClass->get_transact_descriptor(types,
432 &method)));
433
434 // args
435 VariableFactory stubArgs("_arg");
436 {
437 // keep this across different args in order to create the classloader
438 // at most once.
439 bool is_classloader_created = false;
440 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
441 const Type* t = arg->GetType().GetLanguageType<Type>();
442 Variable* v = stubArgs.Get(t);
443 v->dimension = arg->GetType().IsArray() ? 1 : 0;
444
445 statements->Add(new VariableDeclaration(v));
446
447 if (arg->GetDirection() & AidlArgument::IN_DIR) {
448 string code;
449 CodeWriterPtr writer = CodeWriter::ForString(&code);
450 CodeGeneratorContext context{.writer = *(writer.get()),
451 .typenames = types->typenames_,
452 .type = arg->GetType(),
453 .var = v->name,
454 .parcel = transact_data->name,
455 .is_classloader_created = &is_classloader_created};
456 CreateFromParcelFor(context);
457 writer->Close();
458 statements->Add(new LiteralStatement(code));
459 } else {
460 if (!arg->GetType().IsArray()) {
461 statements->Add(new Assignment(v, new NewExpression(t->InstantiableName())));
462 } else {
463 generate_new_array(t, statements, v, transact_data, types);
464 }
465 }
466
467 realCall->arguments.push_back(v);
468 }
469 }
470
471 if (options.GenTraces()) {
472 // try and finally, but only when generating trace code
473 tryStatement = new TryStatement();
474 finallyStatement = new FinallyStatement();
475
476 tryStatement->statements->Add(new MethodCall(
477 new LiteralExpression("android.os.Trace"), "traceBegin", 2,
478 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
479 new StringLiteralExpression(iface.GetName() + "::"
480 + method.GetName() + "::server")));
481
482 finallyStatement->statements->Add(new MethodCall(
483 new LiteralExpression("android.os.Trace"), "traceEnd", 1,
484 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
485 }
486
487 // the real call
488 if (method.GetType().GetName() == "void") {
489 if (options.GenTraces()) {
490 statements->Add(tryStatement);
491 tryStatement->statements->Add(realCall);
492 statements->Add(finallyStatement);
493 } else {
494 statements->Add(realCall);
495 }
496
497 if (!oneway) {
498 // report that there were no exceptions
499 MethodCall* ex =
500 new MethodCall(transact_reply, "writeNoException", 0);
501 statements->Add(ex);
502 }
503 } else {
504 Variable* _result = new Variable(method.GetType().GetLanguageType<Type>()->JavaType(),
505 "_result", method.GetType().IsArray() ? 1 : 0);
506 if (options.GenTraces()) {
507 statements->Add(new VariableDeclaration(_result));
508 statements->Add(tryStatement);
509 tryStatement->statements->Add(new Assignment(_result, realCall));
510 statements->Add(finallyStatement);
511 } else {
512 statements->Add(new VariableDeclaration(_result, realCall));
513 }
514
515 if (!oneway) {
516 // report that there were no exceptions
517 MethodCall* ex =
518 new MethodCall(transact_reply, "writeNoException", 0);
519 statements->Add(ex);
520 }
521
522 // marshall the return value
523 generate_write_to_parcel(method.GetType(), statements, _result, transact_reply, true,
524 types->typenames_);
525 }
526
527 // out parameters
528 int i = 0;
529 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
530 Variable* v = stubArgs.Get(i++);
531
532 if (arg->GetDirection() & AidlArgument::OUT_DIR) {
533 generate_write_to_parcel(arg->GetType(), statements, v, transact_reply, true,
534 types->typenames_);
535 }
536 }
537
538 // return true
539 statements->Add(new ReturnStatement(TRUE_VALUE));
540 }
541
generate_stub_case(const AidlInterface & iface,const AidlMethod & method,const std::string & transactCodeName,bool oneway,StubClass * stubClass,JavaTypeNamespace * types,const Options & options)542 static void generate_stub_case(const AidlInterface& iface, const AidlMethod& method,
543 const std::string& transactCodeName, bool oneway,
544 StubClass* stubClass, JavaTypeNamespace* types,
545 const Options& options) {
546 Case* c = new Case(transactCodeName);
547
548 generate_stub_code(iface, method, oneway, stubClass->transact_data, stubClass->transact_reply,
549 types, c->statements, stubClass, options);
550
551 stubClass->transact_switch->cases.push_back(c);
552 }
553
generate_stub_case_outline(const AidlInterface & iface,const AidlMethod & method,const std::string & transactCodeName,bool oneway,StubClass * stubClass,JavaTypeNamespace * types,const Options & options)554 static void generate_stub_case_outline(const AidlInterface& iface, const AidlMethod& method,
555 const std::string& transactCodeName, bool oneway,
556 StubClass* stubClass, JavaTypeNamespace* types,
557 const Options& options) {
558 std::string outline_name = "onTransact$" + method.GetName() + "$";
559 // Generate an "outlined" method with the actual code.
560 {
561 Variable* transact_data = new Variable(types->ParcelType()->JavaType(), "data");
562 Variable* transact_reply = new Variable(types->ParcelType()->JavaType(), "reply");
563 Method* onTransact_case = new Method;
564 onTransact_case->modifiers = PRIVATE;
565 onTransact_case->returnType = types->BoolType()->JavaType();
566 onTransact_case->name = outline_name;
567 onTransact_case->parameters.push_back(transact_data);
568 onTransact_case->parameters.push_back(transact_reply);
569 onTransact_case->statements = new StatementBlock;
570 onTransact_case->exceptions.push_back(types->RemoteExceptionType()->JavaType());
571 stubClass->elements.push_back(onTransact_case);
572
573 generate_stub_code(iface, method, oneway, transact_data, transact_reply, types,
574 onTransact_case->statements, stubClass, options);
575 }
576
577 // Generate the case dispatch.
578 {
579 Case* c = new Case(transactCodeName);
580
581 MethodCall* helper_call = new MethodCall(THIS_VALUE,
582 outline_name,
583 2,
584 stubClass->transact_data,
585 stubClass->transact_reply);
586 c->statements->Add(new ReturnStatement(helper_call));
587
588 stubClass->transact_switch->cases.push_back(c);
589 }
590 }
591
generate_proxy_method(const AidlInterface & iface,const AidlMethod & method,const std::string & transactCodeName,bool oneway,ProxyClass * proxyClass,JavaTypeNamespace * types,const Options & options)592 static std::unique_ptr<Method> generate_proxy_method(
593 const AidlInterface& iface, const AidlMethod& method, const std::string& transactCodeName,
594 bool oneway, ProxyClass* proxyClass, JavaTypeNamespace* types, const Options& options) {
595 std::unique_ptr<Method> proxy(new Method);
596 proxy->comment = method.GetComments();
597 proxy->modifiers = PUBLIC | OVERRIDE;
598 proxy->returnType = method.GetType().GetLanguageType<Type>()->JavaType();
599 proxy->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
600 proxy->name = method.GetName();
601 proxy->statements = new StatementBlock;
602 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
603 proxy->parameters.push_back(new Variable(arg->GetType().GetLanguageType<Type>()->JavaType(),
604 arg->GetName(), arg->GetType().IsArray() ? 1 : 0));
605 }
606 proxy->exceptions.push_back(types->RemoteExceptionType()->JavaType());
607
608 // the parcels
609 Variable* _data = new Variable(types->ParcelType()->JavaType(), "_data");
610 proxy->statements->Add(
611 new VariableDeclaration(_data, new MethodCall(types->ParcelType()->JavaType(), "obtain")));
612 Variable* _reply = nullptr;
613 if (!oneway) {
614 _reply = new Variable(types->ParcelType()->JavaType(), "_reply");
615 proxy->statements->Add(
616 new VariableDeclaration(_reply, new MethodCall(types->ParcelType()->JavaType(), "obtain")));
617 }
618
619 // the return value
620 Variable* _result = nullptr;
621 if (method.GetType().GetName() != "void") {
622 _result = new Variable(*proxy->returnType, "_result", method.GetType().IsArray() ? 1 : 0);
623 proxy->statements->Add(new VariableDeclaration(_result));
624 }
625
626 // try and finally
627 TryStatement* tryStatement = new TryStatement();
628 proxy->statements->Add(tryStatement);
629 FinallyStatement* finallyStatement = new FinallyStatement();
630 proxy->statements->Add(finallyStatement);
631
632 if (options.GenTraces()) {
633 tryStatement->statements->Add(new MethodCall(
634 new LiteralExpression("android.os.Trace"), "traceBegin", 2,
635 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
636 new StringLiteralExpression(iface.GetName() + "::" +
637 method.GetName() + "::client")));
638 }
639
640 // the interface identifier token: the DESCRIPTOR constant, marshalled as a
641 // string
642 tryStatement->statements->Add(new MethodCall(
643 _data, "writeInterfaceToken", 1, new LiteralExpression("DESCRIPTOR")));
644
645 // the parameters
646 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
647 const Type* t = arg->GetType().GetLanguageType<Type>();
648 Variable* v = new Variable(t->JavaType(), arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
649 AidlArgument::Direction dir = arg->GetDirection();
650 if (dir == AidlArgument::OUT_DIR && arg->GetType().IsArray()) {
651 IfStatement* checklen = new IfStatement();
652 checklen->expression = new Comparison(v, "==", NULL_VALUE);
653 checklen->statements->Add(
654 new MethodCall(_data, "writeInt", 1, new LiteralExpression("-1")));
655 checklen->elseif = new IfStatement();
656 checklen->elseif->statements->Add(
657 new MethodCall(_data, "writeInt", 1, new FieldVariable(v, "length")));
658 tryStatement->statements->Add(checklen);
659 } else if (dir & AidlArgument::IN_DIR) {
660 generate_write_to_parcel(arg->GetType(), tryStatement->statements, v, _data, false,
661 types->typenames_);
662 } else {
663 delete v;
664 }
665 }
666
667 // the transact call
668 unique_ptr<MethodCall> call(new MethodCall(
669 proxyClass->mRemote, "transact", 4, new LiteralExpression("Stub." + transactCodeName), _data,
670 _reply ? _reply : NULL_VALUE,
671 new LiteralExpression(oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0")));
672 unique_ptr<Variable> _status(new Variable(types->BoolType()->JavaType(), "_status"));
673 tryStatement->statements->Add(new VariableDeclaration(_status.release(), call.release()));
674
675 // If the transaction returns false, which means UNKNOWN_TRANSACTION, fall
676 // back to the local method in the default impl, if set before.
677 vector<string> arg_names;
678 for (const auto& arg : method.GetArguments()) {
679 arg_names.emplace_back(arg->GetName());
680 }
681 bool has_return_type = method.GetType().GetName() != "void";
682 tryStatement->statements->Add(new LiteralStatement(
683 android::base::StringPrintf(has_return_type ? "if (!_status && getDefaultImpl() != null) {\n"
684 " return getDefaultImpl().%s(%s);\n"
685 "}\n"
686 : "if (!_status && getDefaultImpl() != null) {\n"
687 " getDefaultImpl().%s(%s);\n"
688 " return;\n"
689 "}\n",
690 method.GetName().c_str(), Join(arg_names, ", ").c_str())));
691
692 // throw back exceptions.
693 if (_reply) {
694 MethodCall* ex = new MethodCall(_reply, "readException", 0);
695 tryStatement->statements->Add(ex);
696 }
697
698 // returning and cleanup
699 if (_reply != nullptr) {
700 // keep this across return value and arguments in order to create the
701 // classloader at most once.
702 bool is_classloader_created = false;
703 if (_result != nullptr) {
704 string code;
705 CodeWriterPtr writer = CodeWriter::ForString(&code);
706 CodeGeneratorContext context{.writer = *(writer.get()),
707 .typenames = types->typenames_,
708 .type = method.GetType(),
709 .var = _result->name,
710 .parcel = _reply->name,
711 .is_classloader_created = &is_classloader_created};
712 CreateFromParcelFor(context);
713 writer->Close();
714 tryStatement->statements->Add(new LiteralStatement(code));
715 }
716
717 // the out/inout parameters
718 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
719 if (arg->GetDirection() & AidlArgument::OUT_DIR) {
720 string code;
721 CodeWriterPtr writer = CodeWriter::ForString(&code);
722 CodeGeneratorContext context{.writer = *(writer.get()),
723 .typenames = types->typenames_,
724 .type = arg->GetType(),
725 .var = arg->GetName(),
726 .parcel = _reply->name,
727 .is_classloader_created = &is_classloader_created};
728 ReadFromParcelFor(context);
729 writer->Close();
730 tryStatement->statements->Add(new LiteralStatement(code));
731 }
732 }
733
734 finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
735 }
736 finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
737
738 if (options.GenTraces()) {
739 finallyStatement->statements->Add(new MethodCall(
740 new LiteralExpression("android.os.Trace"), "traceEnd", 1,
741 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
742 }
743
744 if (_result != nullptr) {
745 proxy->statements->Add(new ReturnStatement(_result));
746 }
747
748 return proxy;
749 }
750
generate_methods(const AidlInterface & iface,const AidlMethod & method,Class * interface,StubClass * stubClass,ProxyClass * proxyClass,int index,JavaTypeNamespace * types,const Options & options)751 static void generate_methods(const AidlInterface& iface, const AidlMethod& method, Class* interface,
752 StubClass* stubClass, ProxyClass* proxyClass, int index,
753 JavaTypeNamespace* types, const Options& options) {
754 const bool oneway = method.IsOneway();
755
756 // == the TRANSACT_ constant =============================================
757 string transactCodeName = "TRANSACTION_";
758 transactCodeName += method.GetName();
759
760 Field* transactCode =
761 new Field(STATIC | FINAL, new Variable(types->IntType()->JavaType(), transactCodeName));
762 transactCode->value =
763 StringPrintf("(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
764 stubClass->elements.push_back(transactCode);
765
766 // getTransactionName
767 if (options.GenTransactionNames()) {
768 Case* c = new Case(transactCodeName);
769 c->statements->Add(new ReturnStatement(new StringLiteralExpression(method.GetName())));
770 stubClass->code_to_method_name_switch->cases.push_back(c);
771 }
772
773 // == the declaration in the interface ===================================
774 ClassElement* decl;
775 if (method.IsUserDefined()) {
776 decl = generate_interface_method(method, types).release();
777 } else {
778 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
779 std::ostringstream code;
780 code << "public int " << kGetInterfaceVersion << "() "
781 << "throws android.os.RemoteException;\n";
782 decl = new LiteralClassElement(code.str());
783 }
784 }
785 interface->elements.push_back(decl);
786
787 // == the stub method ====================================================
788 if (method.IsUserDefined()) {
789 bool outline_stub =
790 stubClass->transact_outline && stubClass->outline_methods.count(&method) != 0;
791 if (outline_stub) {
792 generate_stub_case_outline(iface, method, transactCodeName, oneway, stubClass, types,
793 options);
794 } else {
795 generate_stub_case(iface, method, transactCodeName, oneway, stubClass, types, options);
796 }
797 } else {
798 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
799 Case* c = new Case(transactCodeName);
800 std::ostringstream code;
801 code << "data.enforceInterface(descriptor);\n"
802 << "reply.writeNoException();\n"
803 << "reply.writeInt(" << kGetInterfaceVersion << "());\n"
804 << "return true;\n";
805 c->statements->Add(new LiteralStatement(code.str()));
806 stubClass->transact_switch->cases.push_back(c);
807 }
808 }
809
810 // == the proxy method ===================================================
811 ClassElement* proxy = nullptr;
812 if (method.IsUserDefined()) {
813 proxy =
814 generate_proxy_method(iface, method, transactCodeName, oneway, proxyClass, types, options)
815 .release();
816
817 } else {
818 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
819 std::ostringstream code;
820 code << "@Override\n"
821 << "public int " << kGetInterfaceVersion << "()"
822 << " throws "
823 << "android.os.RemoteException {\n"
824 << " if (mCachedVersion == -1) {\n"
825 << " android.os.Parcel data = android.os.Parcel.obtain();\n"
826 << " android.os.Parcel reply = android.os.Parcel.obtain();\n"
827 << " try {\n"
828 << " data.writeInterfaceToken(DESCRIPTOR);\n"
829 << " mRemote.transact(Stub." << transactCodeName << ", "
830 << "data, reply, 0);\n"
831 << " reply.readException();\n"
832 << " mCachedVersion = reply.readInt();\n"
833 << " } finally {\n"
834 << " reply.recycle();\n"
835 << " data.recycle();\n"
836 << " }\n"
837 << " }\n"
838 << " return mCachedVersion;\n"
839 << "}\n";
840 proxy = new LiteralClassElement(code.str());
841 }
842 }
843 if (proxy != nullptr) {
844 proxyClass->elements.push_back(proxy);
845 }
846 }
847
generate_interface_descriptors(StubClass * stub,ProxyClass * proxy,const JavaTypeNamespace * types)848 static void generate_interface_descriptors(StubClass* stub, ProxyClass* proxy,
849 const JavaTypeNamespace* types) {
850 // the interface descriptor transaction handler
851 Case* c = new Case("INTERFACE_TRANSACTION");
852 c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 1,
853 stub->get_transact_descriptor(types,
854 nullptr)));
855 c->statements->Add(new ReturnStatement(TRUE_VALUE));
856 stub->transact_switch->cases.push_back(c);
857
858 // and the proxy-side method returning the descriptor directly
859 Method* getDesc = new Method;
860 getDesc->modifiers = PUBLIC;
861 getDesc->returnType = types->StringType()->JavaType();
862 getDesc->returnTypeDimension = 0;
863 getDesc->name = "getInterfaceDescriptor";
864 getDesc->statements = new StatementBlock;
865 getDesc->statements->Add(
866 new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
867 proxy->elements.push_back(getDesc);
868 }
869
870 // Check whether (some) methods in this interface should be "outlined," that
871 // is, have specific onTransact methods for certain cases. Set up StubClass
872 // metadata accordingly.
873 //
874 // Outlining will be enabled if the interface has more than outline_threshold
875 // methods. In that case, the methods are sorted by number of arguments
876 // (so that more "complex" methods come later), and the first non_outline_count
877 // number of methods not outlined (are kept in the onTransact() method).
878 //
879 // Requirements: non_outline_count <= outline_threshold.
compute_outline_methods(const AidlInterface * iface,StubClass * stub,size_t outline_threshold,size_t non_outline_count)880 static void compute_outline_methods(const AidlInterface* iface,
881 StubClass* stub,
882 size_t outline_threshold,
883 size_t non_outline_count) {
884 CHECK_LE(non_outline_count, outline_threshold);
885 // We'll outline (create sub methods) if there are more than min_methods
886 // cases.
887 stub->transact_outline = iface->GetMethods().size() > outline_threshold;
888 if (stub->transact_outline) {
889 stub->all_method_count = iface->GetMethods().size();
890 std::vector<const AidlMethod*> methods;
891 methods.reserve(iface->GetMethods().size());
892 for (const std::unique_ptr<AidlMethod>& ptr : iface->GetMethods()) {
893 methods.push_back(ptr.get());
894 }
895
896 std::stable_sort(
897 methods.begin(),
898 methods.end(),
899 [](const AidlMethod* m1, const AidlMethod* m2) {
900 return m1->GetArguments().size() < m2->GetArguments().size();
901 });
902
903 stub->outline_methods.insert(methods.begin() + non_outline_count,
904 methods.end());
905 }
906 }
907
generate_default_impl_method(const AidlMethod & method)908 static unique_ptr<ClassElement> generate_default_impl_method(const AidlMethod& method) {
909 unique_ptr<Method> default_method(new Method);
910 default_method->comment = method.GetComments();
911 default_method->modifiers = PUBLIC | OVERRIDE;
912 default_method->returnType = method.GetType().GetLanguageType<Type>()->JavaType();
913 default_method->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
914 default_method->name = method.GetName();
915 default_method->statements = new StatementBlock;
916 for (const auto& arg : method.GetArguments()) {
917 default_method->parameters.push_back(
918 new Variable(arg->GetType().GetLanguageType<Type>()->JavaType(), arg->GetName(),
919 arg->GetType().IsArray() ? 1 : 0));
920 }
921 default_method->exceptions.push_back(method.GetType()
922 .GetLanguageType<Type>()
923 ->GetTypeNamespace()
924 ->RemoteExceptionType()
925 ->JavaType());
926
927 if (method.GetType().GetName() != "void") {
928 const string& defaultValue = DefaultJavaValueOf(method.GetType());
929 default_method->statements->Add(
930 new LiteralStatement(StringPrintf("return %s;\n", defaultValue.c_str())));
931 }
932 return default_method;
933 }
934
generate_default_impl_class(const AidlInterface & iface,const Options & options)935 static unique_ptr<Class> generate_default_impl_class(const AidlInterface& iface,
936 const Options& options) {
937 unique_ptr<Class> default_class(new Class);
938 default_class->comment = "/** Default implementation for " + iface.GetName() + ". */";
939 default_class->modifiers = PUBLIC | STATIC;
940 default_class->what = Class::CLASS;
941 default_class->type = iface.GetLanguageType<InterfaceType>()->GetDefaultImpl()->JavaType();
942 default_class->interfaces.emplace_back(iface.GetLanguageType<InterfaceType>()->JavaType());
943
944 for (const auto& m : iface.GetMethods()) {
945 if (m->IsUserDefined()) {
946 default_class->elements.emplace_back(generate_default_impl_method(*(m.get())).release());
947 } else {
948 if (m->GetName() == kGetInterfaceVersion && options.Version() > 0) {
949 // This is called only when the remote side is not implementing this
950 // method, which is impossible in normal case, because this method is
951 // automatically declared in the interface class and not implementing
952 // it in the remote side is causing compilation error. But if the remote
953 // side somehow managed to not implement it, that's an error and we
954 // report the case by returning -1 here.
955 std::ostringstream code;
956 code << "@Override\n"
957 << "public int " << kGetInterfaceVersion << "() {\n"
958 << " return -1;\n"
959 << "}\n";
960 default_class->elements.emplace_back(new LiteralClassElement(code.str()));
961 }
962 }
963 }
964
965 default_class->elements.emplace_back(
966 new LiteralClassElement("@Override\n"
967 "public android.os.IBinder asBinder() {\n"
968 " return null;\n"
969 "}\n"));
970
971 return default_class;
972 }
973
generate_binder_interface_class(const AidlInterface * iface,JavaTypeNamespace * types,const Options & options)974 Class* generate_binder_interface_class(const AidlInterface* iface, JavaTypeNamespace* types,
975 const Options& options) {
976 const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
977
978 // the interface class
979 Class* interface = new Class;
980 interface->comment = iface->GetComments();
981 interface->modifiers = PUBLIC;
982 interface->what = Class::INTERFACE;
983 interface->type = interfaceType->JavaType();
984 interface->interfaces.push_back(types->IInterfaceType()->JavaType());
985 interface->annotations = generate_java_annotations(*iface);
986
987 if (options.Version()) {
988 std::ostringstream code;
989 code << "/**\n"
990 << " * The version of this interface that the caller is built against.\n"
991 << " * This might be different from what {@link #getInterfaceVersion()\n"
992 << " * getInterfaceVersion} returns as that is the version of the interface\n"
993 << " * that the remote object is implementing.\n"
994 << " */\n"
995 << "public static final int VERSION = " << options.Version() << ";\n";
996 interface->elements.emplace_back(new LiteralClassElement(code.str()));
997 }
998
999 // the default impl class
1000 Class* default_impl = generate_default_impl_class(*iface, options).release();
1001 interface->elements.emplace_back(default_impl);
1002
1003 // the stub inner class
1004 StubClass* stub =
1005 new StubClass(interfaceType->GetStub(), interfaceType, types, options);
1006 interface->elements.push_back(stub);
1007
1008 compute_outline_methods(iface,
1009 stub,
1010 options.onTransact_outline_threshold_,
1011 options.onTransact_non_outline_count_);
1012
1013 // the proxy inner class
1014 ProxyClass* proxy = new ProxyClass(types, interfaceType->GetProxy(), interfaceType, options);
1015 stub->elements.push_back(proxy);
1016
1017 // stub and proxy support for getInterfaceDescriptor()
1018 generate_interface_descriptors(stub, proxy, types);
1019
1020 // all the declared constants of the interface
1021 for (const auto& constant : iface->GetConstantDeclarations()) {
1022 const AidlConstantValue& value = constant->GetValue();
1023
1024 switch (value.GetType()) {
1025 case AidlConstantValue::Type::STRING: {
1026 generate_string_constant(interface, constant->GetName(),
1027 constant->ValueString(ConstantValueDecorator));
1028 break;
1029 }
1030 case AidlConstantValue::Type::INTEGRAL:
1031 case AidlConstantValue::Type::HEXIDECIMAL: {
1032 generate_int_constant(interface, constant->GetName(),
1033 constant->ValueString(ConstantValueDecorator));
1034 break;
1035 }
1036 default: {
1037 LOG(FATAL) << "Unrecognized constant type: " << static_cast<int>(value.GetType());
1038 }
1039 }
1040 }
1041
1042 // all the declared methods of the interface
1043
1044 for (const auto& item : iface->GetMethods()) {
1045 generate_methods(*iface,
1046 *item,
1047 interface,
1048 stub,
1049 proxy,
1050 item->GetId(),
1051 types,
1052 options);
1053 }
1054
1055 // additional static methods for the default impl set/get to the
1056 // stub class. Can't add them to the interface as the generated java files
1057 // may be compiled with Java < 1.7 where static interface method isn't
1058 // supported.
1059 // TODO(b/111417145) make this conditional depending on the Java language
1060 // version requested
1061 const string i_name = interfaceType->JavaType();
1062 stub->elements.emplace_back(new LiteralClassElement(
1063 StringPrintf("public static boolean setDefaultImpl(%s impl) {\n"
1064 " if (Stub.Proxy.sDefaultImpl == null && impl != null) {\n"
1065 " Stub.Proxy.sDefaultImpl = impl;\n"
1066 " return true;\n"
1067 " }\n"
1068 " return false;\n"
1069 "}\n",
1070 i_name.c_str())));
1071 stub->elements.emplace_back(
1072 new LiteralClassElement(StringPrintf("public static %s getDefaultImpl() {\n"
1073 " return Stub.Proxy.sDefaultImpl;\n"
1074 "}\n",
1075 i_name.c_str())));
1076
1077 // the static field is defined in the proxy class, not in the interface class
1078 // because all fields in an interface class are by default final.
1079 proxy->elements.emplace_back(new LiteralClassElement(
1080 StringPrintf("public static %s sDefaultImpl;\n", i_name.c_str())));
1081
1082 stub->finish();
1083
1084 return interface;
1085 }
1086
1087 } // namespace java
1088 } // namespace android
1089 } // namespace aidl
1090