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