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 #include <string.h>
     23 
     24 #include <android-base/macros.h>
     25 
     26 #include "type_java.h"
     27 
     28 using std::string;
     29 
     30 namespace android {
     31 namespace aidl {
     32 namespace java {
     33 
     34 // =================================================
     35 class StubClass : public Class {
     36  public:
     37   StubClass(const Type* type, const InterfaceType* interfaceType,
     38             JavaTypeNamespace* types);
     39   virtual ~StubClass() = default;
     40 
     41   Variable* transact_code;
     42   Variable* transact_data;
     43   Variable* transact_reply;
     44   Variable* transact_flags;
     45   SwitchStatement* transact_switch;
     46 
     47  private:
     48   void make_as_interface(const InterfaceType* interfaceType,
     49                          JavaTypeNamespace* types);
     50 
     51   DISALLOW_COPY_AND_ASSIGN(StubClass);
     52 };
     53 
     54 StubClass::StubClass(const Type* type, const InterfaceType* interfaceType,
     55                      JavaTypeNamespace* types)
     56     : Class() {
     57   this->comment = "/** Local-side IPC implementation stub class. */";
     58   this->modifiers = PUBLIC | ABSTRACT | STATIC;
     59   this->what = Class::CLASS;
     60   this->type = type;
     61   this->extends = types->BinderNativeType();
     62   this->interfaces.push_back(interfaceType);
     63 
     64   // descriptor
     65   Field* descriptor =
     66       new Field(STATIC | FINAL | PRIVATE,
     67                 new Variable(types->StringType(), "DESCRIPTOR"));
     68   descriptor->value = "\"" + interfaceType->JavaType() + "\"";
     69   this->elements.push_back(descriptor);
     70 
     71   // ctor
     72   Method* ctor = new Method;
     73   ctor->modifiers = PUBLIC;
     74   ctor->comment =
     75       "/** Construct the stub at attach it to the "
     76       "interface. */";
     77   ctor->name = "Stub";
     78   ctor->statements = new StatementBlock;
     79   MethodCall* attach =
     80       new MethodCall(THIS_VALUE, "attachInterface", 2, THIS_VALUE,
     81                      new LiteralExpression("DESCRIPTOR"));
     82   ctor->statements->Add(attach);
     83   this->elements.push_back(ctor);
     84 
     85   // asInterface
     86   make_as_interface(interfaceType, types);
     87 
     88   // asBinder
     89   Method* asBinder = new Method;
     90   asBinder->modifiers = PUBLIC | OVERRIDE;
     91   asBinder->returnType = types->IBinderType();
     92   asBinder->name = "asBinder";
     93   asBinder->statements = new StatementBlock;
     94   asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
     95   this->elements.push_back(asBinder);
     96 
     97   // onTransact
     98   this->transact_code = new Variable(types->IntType(), "code");
     99   this->transact_data = new Variable(types->ParcelType(), "data");
    100   this->transact_reply = new Variable(types->ParcelType(), "reply");
    101   this->transact_flags = new Variable(types->IntType(), "flags");
    102   Method* onTransact = new Method;
    103   onTransact->modifiers = PUBLIC | OVERRIDE;
    104   onTransact->returnType = types->BoolType();
    105   onTransact->name = "onTransact";
    106   onTransact->parameters.push_back(this->transact_code);
    107   onTransact->parameters.push_back(this->transact_data);
    108   onTransact->parameters.push_back(this->transact_reply);
    109   onTransact->parameters.push_back(this->transact_flags);
    110   onTransact->statements = new StatementBlock;
    111   onTransact->exceptions.push_back(types->RemoteExceptionType());
    112   this->elements.push_back(onTransact);
    113   this->transact_switch = new SwitchStatement(this->transact_code);
    114 
    115   onTransact->statements->Add(this->transact_switch);
    116   MethodCall* superCall = new MethodCall(
    117       SUPER_VALUE, "onTransact", 4, this->transact_code, this->transact_data,
    118       this->transact_reply, this->transact_flags);
    119   onTransact->statements->Add(new ReturnStatement(superCall));
    120 }
    121 
    122 void StubClass::make_as_interface(const InterfaceType* interfaceType,
    123                                   JavaTypeNamespace* types) {
    124   Variable* obj = new Variable(types->IBinderType(), "obj");
    125 
    126   Method* m = new Method;
    127   m->comment = "/**\n * Cast an IBinder object into an ";
    128   m->comment += interfaceType->JavaType();
    129   m->comment += " interface,\n";
    130   m->comment += " * generating a proxy if needed.\n */";
    131   m->modifiers = PUBLIC | STATIC;
    132   m->returnType = interfaceType;
    133   m->name = "asInterface";
    134   m->parameters.push_back(obj);
    135   m->statements = new StatementBlock;
    136 
    137   IfStatement* ifstatement = new IfStatement();
    138   ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
    139   ifstatement->statements = new StatementBlock;
    140   ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
    141   m->statements->Add(ifstatement);
    142 
    143   // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
    144   MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
    145   queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
    146   IInterfaceType* iinType = new IInterfaceType(types);
    147   Variable* iin = new Variable(iinType, "iin");
    148   VariableDeclaration* iinVd =
    149       new VariableDeclaration(iin, queryLocalInterface, NULL);
    150   m->statements->Add(iinVd);
    151 
    152   // Ensure the instance type of the local object is as expected.
    153   // One scenario where this is needed is if another package (with a
    154   // different class loader) runs in the same process as the service.
    155 
    156   // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>)
    157   // iin;
    158   Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
    159   Comparison* instOfCheck =
    160       new Comparison(iin, " instanceof ",
    161                      new LiteralExpression(interfaceType->JavaType()));
    162   IfStatement* instOfStatement = new IfStatement();
    163   instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
    164   instOfStatement->statements = new StatementBlock;
    165   instOfStatement->statements->Add(
    166       new ReturnStatement(new Cast(interfaceType, iin)));
    167   m->statements->Add(instOfStatement);
    168 
    169   NewExpression* ne = new NewExpression(interfaceType->GetProxy());
    170   ne->arguments.push_back(obj);
    171   m->statements->Add(new ReturnStatement(ne));
    172 
    173   this->elements.push_back(m);
    174 }
    175 
    176 // =================================================
    177 class ProxyClass : public Class {
    178  public:
    179   ProxyClass(const JavaTypeNamespace* types, const Type* type,
    180              const InterfaceType* interfaceType);
    181   virtual ~ProxyClass();
    182 
    183   Variable* mRemote;
    184   bool mOneWay;
    185 };
    186 
    187 ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type,
    188                        const InterfaceType* interfaceType)
    189     : Class() {
    190   this->modifiers = PRIVATE | STATIC;
    191   this->what = Class::CLASS;
    192   this->type = type;
    193   this->interfaces.push_back(interfaceType);
    194 
    195   mOneWay = interfaceType->OneWay();
    196 
    197   // IBinder mRemote
    198   mRemote = new Variable(types->IBinderType(), "mRemote");
    199   this->elements.push_back(new Field(PRIVATE, mRemote));
    200 
    201   // Proxy()
    202   Variable* remote = new Variable(types->IBinderType(), "remote");
    203   Method* ctor = new Method;
    204   ctor->name = "Proxy";
    205   ctor->statements = new StatementBlock;
    206   ctor->parameters.push_back(remote);
    207   ctor->statements->Add(new Assignment(mRemote, remote));
    208   this->elements.push_back(ctor);
    209 
    210   // IBinder asBinder()
    211   Method* asBinder = new Method;
    212   asBinder->modifiers = PUBLIC | OVERRIDE;
    213   asBinder->returnType = types->IBinderType();
    214   asBinder->name = "asBinder";
    215   asBinder->statements = new StatementBlock;
    216   asBinder->statements->Add(new ReturnStatement(mRemote));
    217   this->elements.push_back(asBinder);
    218 }
    219 
    220 ProxyClass::~ProxyClass() {}
    221 
    222 // =================================================
    223 static void generate_new_array(const Type* t, StatementBlock* addTo,
    224                                Variable* v, Variable* parcel,
    225                                JavaTypeNamespace* types) {
    226   Variable* len = new Variable(types->IntType(), v->name + "_length");
    227   addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
    228   IfStatement* lencheck = new IfStatement();
    229   lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
    230   lencheck->statements->Add(new Assignment(v, NULL_VALUE));
    231   lencheck->elseif = new IfStatement();
    232   lencheck->elseif->statements->Add(
    233       new Assignment(v, new NewArrayExpression(t, len)));
    234   addTo->Add(lencheck);
    235 }
    236 
    237 static void generate_write_to_parcel(const Type* t, StatementBlock* addTo,
    238                                      Variable* v, Variable* parcel, int flags) {
    239   t->WriteToParcel(addTo, v, parcel, flags);
    240 }
    241 
    242 static void generate_create_from_parcel(const Type* t, StatementBlock* addTo,
    243                                         Variable* v, Variable* parcel,
    244                                         Variable** cl) {
    245   t->CreateFromParcel(addTo, v, parcel, cl);
    246 }
    247 
    248 static void generate_int_constant(const AidlIntConstant& constant,
    249                                   Class* interface) {
    250   IntConstant* decl = new IntConstant(constant.GetName(), constant.GetValue());
    251   interface->elements.push_back(decl);
    252 }
    253 
    254 static void generate_string_constant(const AidlStringConstant& constant,
    255                                      Class* interface) {
    256   StringConstant* decl = new StringConstant(constant.GetName(),
    257                                             constant.GetValue());
    258   interface->elements.push_back(decl);
    259 }
    260 
    261 static void generate_method(const AidlMethod& method, Class* interface,
    262                             StubClass* stubClass, ProxyClass* proxyClass,
    263                             int index, JavaTypeNamespace* types) {
    264   int i;
    265 
    266   const bool oneway = proxyClass->mOneWay || method.IsOneway();
    267 
    268   // == the TRANSACT_ constant =============================================
    269   string transactCodeName = "TRANSACTION_";
    270   transactCodeName += method.GetName();
    271 
    272   char transactCodeValue[60];
    273   sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)",
    274           index);
    275 
    276   Field* transactCode = new Field(
    277       STATIC | FINAL, new Variable(types->IntType(), transactCodeName));
    278   transactCode->value = transactCodeValue;
    279   stubClass->elements.push_back(transactCode);
    280 
    281   // == the declaration in the interface ===================================
    282   Method* decl = new Method;
    283   decl->comment = method.GetComments();
    284   decl->modifiers = PUBLIC;
    285   decl->returnType = method.GetType().GetLanguageType<Type>();
    286   decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
    287   decl->name = method.GetName();
    288 
    289   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
    290     decl->parameters.push_back(
    291         new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
    292                      arg->GetType().IsArray() ? 1 : 0));
    293   }
    294 
    295   decl->exceptions.push_back(types->RemoteExceptionType());
    296 
    297   interface->elements.push_back(decl);
    298 
    299   // == the stub method ====================================================
    300 
    301   Case* c = new Case(transactCodeName);
    302 
    303   MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName());
    304 
    305   // interface token validation is the very first thing we do
    306   c->statements->Add(new MethodCall(stubClass->transact_data,
    307                                     "enforceInterface", 1,
    308                                     new LiteralExpression("DESCRIPTOR")));
    309 
    310   // args
    311   Variable* cl = NULL;
    312   VariableFactory stubArgs("_arg");
    313   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
    314     const Type* t = arg->GetType().GetLanguageType<Type>();
    315     Variable* v = stubArgs.Get(t);
    316     v->dimension = arg->GetType().IsArray() ? 1 : 0;
    317 
    318     c->statements->Add(new VariableDeclaration(v));
    319 
    320     if (arg->GetDirection() & AidlArgument::IN_DIR) {
    321       generate_create_from_parcel(t, c->statements, v, stubClass->transact_data,
    322                                   &cl);
    323     } else {
    324       if (!arg->GetType().IsArray()) {
    325         c->statements->Add(new Assignment(v, new NewExpression(v->type)));
    326       } else {
    327         generate_new_array(v->type, c->statements, v, stubClass->transact_data,
    328                            types);
    329       }
    330     }
    331 
    332     realCall->arguments.push_back(v);
    333   }
    334 
    335   cl = NULL;
    336 
    337   // the real call
    338   Variable* _result = NULL;
    339   if (method.GetType().GetName() == "void") {
    340     c->statements->Add(realCall);
    341 
    342     if (!oneway) {
    343       // report that there were no exceptions
    344       MethodCall* ex =
    345           new MethodCall(stubClass->transact_reply, "writeNoException", 0);
    346       c->statements->Add(ex);
    347     }
    348   } else {
    349     _result =
    350         new Variable(decl->returnType, "_result", decl->returnTypeDimension);
    351     c->statements->Add(new VariableDeclaration(_result, realCall));
    352 
    353     if (!oneway) {
    354       // report that there were no exceptions
    355       MethodCall* ex =
    356           new MethodCall(stubClass->transact_reply, "writeNoException", 0);
    357       c->statements->Add(ex);
    358     }
    359 
    360     // marshall the return value
    361     generate_write_to_parcel(decl->returnType, c->statements, _result,
    362                              stubClass->transact_reply,
    363                              Type::PARCELABLE_WRITE_RETURN_VALUE);
    364   }
    365 
    366   // out parameters
    367   i = 0;
    368   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
    369     const Type* t = arg->GetType().GetLanguageType<Type>();
    370     Variable* v = stubArgs.Get(i++);
    371 
    372     if (arg->GetDirection() & AidlArgument::OUT_DIR) {
    373       generate_write_to_parcel(t, c->statements, v, stubClass->transact_reply,
    374                                Type::PARCELABLE_WRITE_RETURN_VALUE);
    375     }
    376   }
    377 
    378   // return true
    379   c->statements->Add(new ReturnStatement(TRUE_VALUE));
    380   stubClass->transact_switch->cases.push_back(c);
    381 
    382   // == the proxy method ===================================================
    383   Method* proxy = new Method;
    384   proxy->comment = method.GetComments();
    385   proxy->modifiers = PUBLIC | OVERRIDE;
    386   proxy->returnType = method.GetType().GetLanguageType<Type>();
    387   proxy->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
    388   proxy->name = method.GetName();
    389   proxy->statements = new StatementBlock;
    390   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
    391     proxy->parameters.push_back(
    392         new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
    393                      arg->GetType().IsArray() ? 1 : 0));
    394   }
    395   proxy->exceptions.push_back(types->RemoteExceptionType());
    396   proxyClass->elements.push_back(proxy);
    397 
    398   // the parcels
    399   Variable* _data = new Variable(types->ParcelType(), "_data");
    400   proxy->statements->Add(new VariableDeclaration(
    401       _data, new MethodCall(types->ParcelType(), "obtain")));
    402   Variable* _reply = NULL;
    403   if (!oneway) {
    404     _reply = new Variable(types->ParcelType(), "_reply");
    405     proxy->statements->Add(new VariableDeclaration(
    406         _reply, new MethodCall(types->ParcelType(), "obtain")));
    407   }
    408 
    409   // the return value
    410   _result = NULL;
    411   if (method.GetType().GetName() != "void") {
    412     _result = new Variable(proxy->returnType, "_result",
    413                            method.GetType().IsArray() ? 1 : 0);
    414     proxy->statements->Add(new VariableDeclaration(_result));
    415   }
    416 
    417   // try and finally
    418   TryStatement* tryStatement = new TryStatement();
    419   proxy->statements->Add(tryStatement);
    420   FinallyStatement* finallyStatement = new FinallyStatement();
    421   proxy->statements->Add(finallyStatement);
    422 
    423   // the interface identifier token: the DESCRIPTOR constant, marshalled as a
    424   // string
    425   tryStatement->statements->Add(new MethodCall(
    426       _data, "writeInterfaceToken", 1, new LiteralExpression("DESCRIPTOR")));
    427 
    428   // the parameters
    429   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
    430     const Type* t = arg->GetType().GetLanguageType<Type>();
    431     Variable* v =
    432         new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
    433     AidlArgument::Direction dir = arg->GetDirection();
    434     if (dir == AidlArgument::OUT_DIR && arg->GetType().IsArray()) {
    435       IfStatement* checklen = new IfStatement();
    436       checklen->expression = new Comparison(v, "==", NULL_VALUE);
    437       checklen->statements->Add(
    438           new MethodCall(_data, "writeInt", 1, new LiteralExpression("-1")));
    439       checklen->elseif = new IfStatement();
    440       checklen->elseif->statements->Add(
    441           new MethodCall(_data, "writeInt", 1, new FieldVariable(v, "length")));
    442       tryStatement->statements->Add(checklen);
    443     } else if (dir & AidlArgument::IN_DIR) {
    444       generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
    445     } else {
    446       delete v;
    447     }
    448   }
    449 
    450   // the transact call
    451   MethodCall* call = new MethodCall(
    452       proxyClass->mRemote, "transact", 4,
    453       new LiteralExpression("Stub." + transactCodeName), _data,
    454       _reply ? _reply : NULL_VALUE,
    455       new LiteralExpression(oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
    456   tryStatement->statements->Add(call);
    457 
    458   // throw back exceptions.
    459   if (_reply) {
    460     MethodCall* ex = new MethodCall(_reply, "readException", 0);
    461     tryStatement->statements->Add(ex);
    462   }
    463 
    464   // returning and cleanup
    465   if (_reply != NULL) {
    466     if (_result != NULL) {
    467       generate_create_from_parcel(proxy->returnType, tryStatement->statements,
    468                                   _result, _reply, &cl);
    469     }
    470 
    471     // the out/inout parameters
    472     for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
    473       const Type* t = arg->GetType().GetLanguageType<Type>();
    474       if (arg->GetDirection() & AidlArgument::OUT_DIR) {
    475         Variable* v =
    476             new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
    477         t->ReadFromParcel(tryStatement->statements, v, _reply, &cl);
    478       }
    479     }
    480 
    481     finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
    482   }
    483   finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
    484 
    485   if (_result != NULL) {
    486     proxy->statements->Add(new ReturnStatement(_result));
    487   }
    488 }
    489 
    490 static void generate_interface_descriptors(StubClass* stub, ProxyClass* proxy,
    491                                            const JavaTypeNamespace* types) {
    492   // the interface descriptor transaction handler
    493   Case* c = new Case("INTERFACE_TRANSACTION");
    494   c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 1,
    495                                     new LiteralExpression("DESCRIPTOR")));
    496   c->statements->Add(new ReturnStatement(TRUE_VALUE));
    497   stub->transact_switch->cases.push_back(c);
    498 
    499   // and the proxy-side method returning the descriptor directly
    500   Method* getDesc = new Method;
    501   getDesc->modifiers = PUBLIC;
    502   getDesc->returnType = types->StringType();
    503   getDesc->returnTypeDimension = 0;
    504   getDesc->name = "getInterfaceDescriptor";
    505   getDesc->statements = new StatementBlock;
    506   getDesc->statements->Add(
    507       new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
    508   proxy->elements.push_back(getDesc);
    509 }
    510 
    511 Class* generate_binder_interface_class(const AidlInterface* iface,
    512                                        JavaTypeNamespace* types) {
    513   const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
    514 
    515   // the interface class
    516   Class* interface = new Class;
    517   interface->comment = iface->GetComments();
    518   interface->modifiers = PUBLIC;
    519   interface->what = Class::INTERFACE;
    520   interface->type = interfaceType;
    521   interface->interfaces.push_back(types->IInterfaceType());
    522 
    523   // the stub inner class
    524   StubClass* stub =
    525       new StubClass(interfaceType->GetStub(), interfaceType, types);
    526   interface->elements.push_back(stub);
    527 
    528   // the proxy inner class
    529   ProxyClass* proxy =
    530       new ProxyClass(types, interfaceType->GetProxy(), interfaceType);
    531   stub->elements.push_back(proxy);
    532 
    533   // stub and proxy support for getInterfaceDescriptor()
    534   generate_interface_descriptors(stub, proxy, types);
    535 
    536   // all the declared constants of the interface
    537   for (const auto& item : iface->GetIntConstants()) {
    538     generate_int_constant(*item, interface);
    539   }
    540   for (const auto& item : iface->GetStringConstants()) {
    541     generate_string_constant(*item, interface);
    542   }
    543 
    544   // all the declared methods of the interface
    545   for (const auto& item : iface->GetMethods()) {
    546     generate_method(*item, interface, stub, proxy, item->GetId(), types);
    547   }
    548 
    549   return interface;
    550 }
    551 
    552 }  // namespace java
    553 }  // namespace android
    554 }  // namespace aidl
    555