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