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