Home | History | Annotate | Download | only in aidl
      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 
     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 
    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.
    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 
    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 
    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 
    284 ProxyClass::~ProxyClass() {}
    285 
    286 // =================================================
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    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