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