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