• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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