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// =================================================
9class StubClass : public Class
10{
11public:
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;
20private:
21    void make_as_interface(Type* interfaceType);
22};
23
24StubClass::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
89StubClass::~StubClass()
90{
91}
92
93void
94StubClass::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// =================================================
149class ProxyClass : public Class
150{
151public:
152    ProxyClass(Type* type, InterfaceType* interfaceType);
153    virtual ~ProxyClass();
154
155    Variable* mRemote;
156    bool mOneWay;
157};
158
159ProxyClass::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
192ProxyClass::~ProxyClass()
193{
194}
195
196// =================================================
197static void
198generate_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
212static void
213generate_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
224static void
225generate_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
236static void
237generate_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
249static void
250generate_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
495static void
496generate_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
516Class*
517generate_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