static void
generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
        EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
        int index)
{
    arg_type* arg;

    // == the callback interface for results ================================
    // the service base class
    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
    
    // == the method in the proxy class =====================================
    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);

    // == the method in the result dispatcher class =========================
    if (resultsInterfaceType != NULL) {
        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
                index);
    }

    // == The abstract method that the service developers implement ==========
    Method* decl = new Method;
        decl->comment = gather_comments(method->comments_token->extra);
        decl->modifiers = PUBLIC | ABSTRACT;
        decl->returnType = NAMES.Search(method->type.type.data);
        decl->returnTypeDimension = method->type.dimension;
        decl->name = method->name.data;
    arg = method->args;
    while (arg != NULL) {
        decl->parameters.push_back(new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension));
        arg = arg->next;
    }

    // Add the default RpcContext param to all methods
    decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
	
    serviceBaseClass->elements.push_back(decl);
    

    // == the dispatch method in the service base class ======================
    serviceBaseClass->AddMethod(method);
}
// =================================================
static Type*
generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
{
    arg_type* arg;

    string resultsMethodName = results_method_name(method->name.data);
    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
            Type::GENERATED, false, false, false);

    if (!method->oneway) {
        Class* resultsClass = new Class;
            resultsClass->modifiers = STATIC | PUBLIC;
            resultsClass->what = Class::INTERFACE;
            resultsClass->type = resultsInterfaceType;

        Method* resultMethod = new Method;
            resultMethod->comment = gather_comments(method->comments_token->extra);
            resultMethod->modifiers = PUBLIC;
            resultMethod->returnType = VOID_TYPE;
            resultMethod->returnTypeDimension = 0;
            resultMethod->name = resultsMethodName;
        if (0 != strcmp("void", method->type.type.data)) {
            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
                        "_result", method->type.dimension));
        }
        arg = method->args;
        while (arg != NULL) {
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                resultMethod->parameters.push_back(new Variable(
                                    NAMES.Search(arg->type.type.data), arg->name.data,
                                    arg->type.dimension));
            }
            arg = arg->next;
        }
        resultsClass->elements.push_back(resultMethod);

        if (resultMethod->parameters.size() > 0) {
            proxyClass->elements.push_back(resultsClass);
            return resultsInterfaceType;
        } 
    }
    //delete resultsInterfaceType;
    return NULL;
}
Class*
generate_binder_interface_class(const interface_type* iface)
{
    InterfaceType* interfaceType = static_cast<InterfaceType*>(
        NAMES.Find(iface->package, iface->name.data));

    // the interface class
    Class* interface = new Class;
        interface->comment = gather_comments(iface->comments_token->extra);
        interface->modifiers = PUBLIC;
        interface->what = Class::INTERFACE;
        interface->type = interfaceType;
        interface->interfaces.push_back(IINTERFACE_TYPE);

    // the stub inner class
    StubClass* stub = new StubClass(
        NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
        interfaceType);
    interface->elements.push_back(stub);

    // the proxy inner class
    ProxyClass* proxy = new ProxyClass(
        NAMES.Find(iface->package,
                         append(iface->name.data, ".Stub.Proxy").c_str()),
        interfaceType);
    stub->elements.push_back(proxy);

    // stub and proxy support for getInterfaceDescriptor()
    generate_interface_descriptors(stub, proxy);

    // all the declared methods of the interface
    int index = 0;
    interface_item_type* item = iface->interface_items;
    while (item != NULL) {
        if (item->item_type == METHOD_TYPE) {
            method_type * method_item = (method_type*) item;
            generate_method(method_item, interface, stub, proxy, method_item->assigned_id);
        }
        item = item->next;
        index++;
    }

    return interface;
}
RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
    :Class()
{
    this->comment = gather_comments(iface->comments_token->extra);
    this->modifiers = PUBLIC;
    this->what = Class::CLASS;
    this->type = interfaceType;

    // broker
    this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
    this->elements.push_back(new Field(PRIVATE, this->broker));
    // endpoint
    this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
    this->elements.push_back(new Field(PRIVATE, this->endpoint));

    // methods
    generate_ctor();
    generate_get_endpoint_info();
}
static void
generate_method(const method_type* method, Class* interface,
                    StubClass* stubClass, ProxyClass* proxyClass, int index)
{
    arg_type* arg;
    int i;
    bool hasOutParams = false;

    const bool oneway = proxyClass->mOneWay || method->oneway;

    // == the TRANSACT_ constant =============================================
    string transactCodeName = "TRANSACTION_";
    transactCodeName += method->name.data;

    //char transactCodeValue[60];
    //sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);

    //Field* transactCode = new Field(STATIC | FINAL,
    //                        new Variable(INT_TYPE, transactCodeName));
    //transactCode->value = transactCodeValue;
    //interface->elements.push_back(transactCode);

    if (interface->methodEnum == 0) interface->methodEnum = new Enum();
    EnumItem* item = new EnumItem();
    item->name = transactCodeName;
    if (interface->methodEnum->items.size() == 0) item->value = "IBinder::FIRST_CALL_TRANSACTION";
    else item->value = "";
    interface->methodEnum->items.push_back(item);
    interface->declareMetaInterfaceName = string(interface->type->Name().c_str() + 1);
    interface->implementMetaInterfaceName = string(interface->type->Name().c_str() + 1);

    // +JDN
    //interface->implementMetaInterfaceDesc = interface->type->CPPQualifiedName();
    interface->implementMetaInterfaceDesc = interface->type->QualifiedName();
    // -JDN

    // == the declaration in the interface ===================================
    Method* decl = new Method;
        decl->comment = gather_comments(method->comments_token->extra);
        decl->modifiers = VIRTUAL;
        decl->returnType = NAMES.Search(method->type.type.data);
        decl->returnTypeDimension = method->type.dimension;
        decl->name = method->name.data;

    arg = method->args;
    while (arg != NULL) {
        Type* vType = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(
                    vType, arg->name.data,
                    arg->type.dimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(vType);
        if (userDataType != NULL) {
            v->modifiers = POINTER;
        }
        decl->parameters.push_back(v);
        arg = arg->next;
    }

    // No exception in C++
    //decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);

    interface->elements.push_back(decl);

    // == the stub method ====================================================

    Case* c = new Case(transactCodeName);

    Variable* thisVar = new Variable(interface->type, "this");
    thisVar->modifiers = POINTER;
    MethodCall* realCall = new MethodCall(thisVar/*THIS_VALUE*/, method->name.data);

    // interface token validation is the very first thing we do

    string getDescriptor = interface->type->Name() + string("::getInterfaceDescriptor()");

    // +JDN Don t do checkInterface + enforceInterface it broke serialization
    // c->statements->Add(new MethodCall(stubClass->transact_data,
    //        "enforceInterface", 1, new LiteralExpression(getDescriptor/*"DESCRIPTOR"*/)));
    // -JDN

    // args
    Variable* cl = NULL;
    VariableFactory stubArgs("_arg");
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(t);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(t);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(t);
        if (userDataType != NULL) v->modifiers |= POINTER;
        else if (interfaceType != NULL) v->modifiers |= STRONG_POINTER;
        //if (userDataType != NULL) v->modifiers |= CALL_POINTER;
        v->dimension = arg->type.dimension;

        c->statements->Add(new VariableDeclaration(v));

        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_parcel(t, c->statements, v,
                    stubClass->transact_data, &cl);
        } else {
            if (arg->type.dimension == 0) {
                c->statements->Add(new Assignment(v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, c->statements, v,
                        stubClass->transact_data);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // the real call
    Variable* _result = NULL;
    if (0 == strcmp(method->type.type.data, "void")) {
        c->statements->Add(realCall);

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }
    } else {
        _result = new Variable(decl->returnType, "_result",
                                decl->returnTypeDimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(decl->returnType);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(decl->returnType);
        if (userDataType != NULL) _result->modifiers = POINTER;
        else if (interfaceType != NULL) _result->modifiers = STRONG_POINTER;
        c->statements->Add(new VariableDeclaration(_result, realCall));

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }

        // marshall the return value
        generate_write_to_parcel(decl->returnType, c->statements, _result,
                                    stubClass->transact_reply,
                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
    }

    // out parameters
    i = 0;
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(i++);

        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            generate_write_to_parcel(t, c->statements, v,
                                stubClass->transact_reply,
                                Type::PARCELABLE_WRITE_RETURN_VALUE);
            hasOutParams = true;
        }

        arg = arg->next;
    }

    // return true
    c->statements->Add(new ReturnStatement(new LiteralExpression("NO_ERROR")));
    stubClass->transact_switch->cases.push_back(c);

    // == the proxy method ===================================================
    Method* proxy = new Method;
        proxy->comment = gather_comments(method->comments_token->extra);
        proxy->modifiers = PUBLIC | OVERRIDE;
        proxy->returnType = NAMES.Search(method->type.type.data);
        proxy->returnTypeDimension = method->type.dimension;
        proxy->name = method->name.data;
        proxy->statements = new StatementBlock;
        proxy->classType = proxyClass->type;
        arg = method->args;
        while (arg != NULL) {
            Type* vType = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(
                        vType, arg->name.data,
                        arg->type.dimension);
            UserDataType* userDataType = dynamic_cast<UserDataType*>(vType);
            InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(vType);
            if (userDataType != NULL) {
                v->modifiers |= POINTER;
            } else if (interfaceType != NULL) {
                v->modifiers |= STRONG_POINTER;
            }
            proxy->parameters.push_back(v/*new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension)*/);
            arg = arg->next;
        }
        //proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
    proxyClass->elements.push_back(proxy);

    // the parcels
    Variable* _data = new Variable(PARCEL_TYPE, "_data");
    //proxy->statements->Add(new VariableDeclaration(_data,
    //                            new MethodCall(PARCEL_TYPE, "obtain")));
    proxy->statements->Add(new VariableDeclaration(_data));

    Variable* _reply = NULL;
    if (!oneway) {
        _reply = new Variable(PARCEL_TYPE, "_reply");
        //proxy->statements->Add(new VariableDeclaration(_reply,
        //                            new MethodCall(PARCEL_TYPE, "obtain")));
        proxy->statements->Add(new VariableDeclaration(_reply));
    }

    // the return value
    _result = NULL;
    if (0 != strcmp(method->type.type.data, "void")) {
        _result = new Variable(proxy->returnType, "_result",
                method->type.dimension);
        UserDataType* userDataType = dynamic_cast<UserDataType*>(proxy->returnType);
        InterfaceType* interfaceType = dynamic_cast<InterfaceType*>(proxy->returnType);
        if (userDataType != NULL) {
            _result->modifiers = POINTER;
        } else if (interfaceType != NULL) {
            _result->modifiers = STRONG_POINTER;
        }
        proxy->statements->Add(new VariableDeclaration(_result));
    }

    // try and finally
    //TryStatement* tryStatement = new TryStatement();
    //proxy->statements->Add(tryStatement);
    //FinallyStatement* finallyStatement = new FinallyStatement();
    //proxy->statements->Add(finallyStatement);

    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string

    /*tryStatement*/proxy->statements->Add(new MethodCall(_data, "writeInterfaceToken",
            1, new LiteralExpression(getDescriptor/*"DESCRIPTOR"*/)));

    // the parameters
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
        int dir = convert_direction(arg->direction.data);
        v->modifiers |= POINTER;
        if (dir == OUT_PARAMETER && arg->type.dimension != 0)
		{
            IfStatement* checklen = new IfStatement();
            checklen->expression = new Comparison(v, "==", NULL_VALUE);
            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
                        new LiteralExpression("-1")));
            checklen->elseif = new IfStatement();
            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
                        1, new FieldVariable(v, "length")));
            /*tryStatement*/proxy->statements->Add(checklen);
        }
        else if (dir & IN_PARAMETER)
        {
            // +JDN
            // ALERT LEAK !!!!
            Variable* localParcel = new Variable();
            localParcel->type = _data->type;
            localParcel->name = _data->name;
            localParcel->dimension = _data->dimension;
            localParcel->modifiers = _data->modifiers;
            localParcel->modifiers |= CALL_REFERENCE;
            // printf("generating parcel for %s (%s)\n", v->name.c_str(), v->type->Name().c_str());
            //generate_write_to_parcel(t, /*tryStatement*/proxy->statements, v, _data, 0);
            generate_write_to_parcel(t, /*tryStatement*/proxy->statements, v, localParcel, 0);
            // -JDN
        }
        else
        {
            // printf("else\n", "");
            // Do nothing
        }
        arg = arg->next;
    }

    // the transact call
    Variable* callReply = NULL;
    if (_reply != NULL) {
        callReply = new Variable(_reply->type, _reply->name);
        callReply->modifiers = CALL_REFERENCE;
    }
    MethodCall* call = new MethodCall(/*proxyClass->mRemote*/ new LiteralExpression("(*(remote()))"), "transact", 4,
                            new LiteralExpression(/*"Stub." +*/ transactCodeName),
                            _data, callReply ? callReply : NULL_VALUE,
                            new LiteralExpression(
                                          oneway ? /*"android.os.IBinder.FLAG_ONEWAY"*/ "IBinder::FLAG_ONEWAY" : "0"));
    /*tryStatement*/proxy->statements->Add(call);

    // throw back exceptions.
    if (_reply) {
        MethodCall* ex = new MethodCall(_reply, "readExceptionCode", 0);
        /*tryStatement*/proxy->statements->Add(ex);
    }

    // returning and cleanup
    if (_reply != NULL) {
        if (_result != NULL) {
            generate_create_from_parcel(proxy->returnType,
                    /*tryStatement*/proxy->statements, _result, _reply, &cl);
        }

        // the out/inout parameters
        arg = method->args;
        while (arg != NULL) {
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            UserDataType* userDataType = dynamic_cast<UserDataType*>(t);
            if (userDataType != NULL) v->modifiers = POINTER;
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                generate_read_from_parcel(t, /*tryStatement*/proxy->statements,
                                            v, _reply, &cl);
            }
            arg = arg->next;
        }

        //finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
    }
    //finallyStatement->statements->Add(new MethodCall(_data, "recycle"));

    if (_result != NULL) {
        proxy->statements->Add(new ReturnStatement(_result));
    }
}
static void
generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
{
    arg_type* arg;
    Method* proxyMethod = new Method;
        proxyMethod->comment = gather_comments(method->comments_token->extra);
        proxyMethod->modifiers = PUBLIC;
        proxyMethod->returnType = VOID_TYPE;
        proxyMethod->returnTypeDimension = 0;
        proxyMethod->name = method->name.data;
        proxyMethod->statements = new StatementBlock;
    proxyClass->elements.push_back(proxyMethod);

    // The local variables
    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));

    // Add the arguments
    arg = method->args;
    while (arg != NULL) {
        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            // Function signature
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            proxyMethod->parameters.push_back(v);

            // Input parameter marshalling
            generate_write_to_data(t, proxyMethod->statements,
                    new StringLiteralExpression(arg->name.data), v, _data);
        }
        arg = arg->next;
    }

    // If there is a results interface for this class
    Expression* resultParameter;
    if (resultsInterfaceType != NULL) {
        // Result interface parameter
        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
        proxyMethod->parameters.push_back(resultListener);

        // Add the results dispatcher callback
        resultsDispatcherClass->needed = true;
        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
                new LiteralExpression(format_int(index)), resultListener);
    } else {
        resultParameter = NULL_VALUE;
    }

    // All proxy methods take an error parameter
    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
    proxyMethod->parameters.push_back(errorListener);

    // Call the broker
    proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
                "sendRpc", 5,
                proxyClass->endpoint,
                new StringLiteralExpression(method->name.data),
                new MethodCall(_data, "serialize"),
                resultParameter,
                errorListener));
}
static void
generate_method(const method_type* method, Class* interface,
                    StubClass* stubClass, ProxyClass* proxyClass, int index)
{
    arg_type* arg;
    int i;
    bool hasOutParams = false;

    const bool oneway = proxyClass->mOneWay || method->oneway;

    // == the TRANSACT_ constant =============================================
    string transactCodeName = "TRANSACTION_";
    transactCodeName += method->name.data;

    char transactCodeValue[50];
    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);

    Field* transactCode = new Field(STATIC | FINAL,
                            new Variable(INT_TYPE, transactCodeName));
    transactCode->value = transactCodeValue;
    stubClass->elements.push_back(transactCode);

    // == the declaration in the interface ===================================
    Method* decl = new Method;
        decl->comment = gather_comments(method->comments_token->extra);
        decl->modifiers = PUBLIC;
        decl->returnType = NAMES.Search(method->type.type.data);
        decl->returnTypeDimension = method->type.dimension;
        decl->name = method->name.data;

    arg = method->args;
    while (arg != NULL) {
        decl->parameters.push_back(new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension));
        arg = arg->next;
    }

    decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);

    interface->elements.push_back(decl);

    // == the stub method ====================================================

    Case* c = new Case(transactCodeName);

    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);

    // interface token validation is the very first thing we do
    c->statements->Add(new MethodCall(stubClass->transact_data,
            "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));

    // args
    Variable* cl = NULL;
    VariableFactory stubArgs("_arg");
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(t);
        v->dimension = arg->type.dimension;

        c->statements->Add(new VariableDeclaration(v));

        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_parcel(t, c->statements, v,
                    stubClass->transact_data, &cl);
        } else {
            if (arg->type.dimension == 0) {
                c->statements->Add(new Assignment(
                                                v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, c->statements, v,
                        stubClass->transact_data);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // the real call
    Variable* _result = NULL;
    if (0 == strcmp(method->type.type.data, "void")) {
        c->statements->Add(realCall);

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }
    } else {
        _result = new Variable(decl->returnType, "_result",
                                decl->returnTypeDimension);
        c->statements->Add(new VariableDeclaration(_result, realCall));

        if (!oneway) {
            // report that there were no exceptions
            MethodCall* ex = new MethodCall(stubClass->transact_reply,
                    "writeNoException", 0);
            c->statements->Add(ex);
        }

        // marshall the return value
        generate_write_to_parcel(decl->returnType, c->statements, _result,
                                    stubClass->transact_reply,
                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
    }

    // out parameters
    i = 0;
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = stubArgs.Get(i++);

        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            generate_write_to_parcel(t, c->statements, v,
                                stubClass->transact_reply,
                                Type::PARCELABLE_WRITE_RETURN_VALUE);
            hasOutParams = true;
        }

        arg = arg->next;
    }

    // return true
    c->statements->Add(new ReturnStatement(TRUE_VALUE));
    stubClass->transact_switch->cases.push_back(c);

    // == the proxy method ===================================================
    Method* proxy = new Method;
        proxy->comment = gather_comments(method->comments_token->extra);
        proxy->modifiers = PUBLIC;
        proxy->returnType = NAMES.Search(method->type.type.data);
        proxy->returnTypeDimension = method->type.dimension;
        proxy->name = method->name.data;
        proxy->statements = new StatementBlock;
        arg = method->args;
        while (arg != NULL) {
            proxy->parameters.push_back(new Variable(
                            NAMES.Search(arg->type.type.data), arg->name.data,
                            arg->type.dimension));
            arg = arg->next;
        }
        proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
    proxyClass->elements.push_back(proxy);

    // the parcels
    Variable* _data = new Variable(PARCEL_TYPE, "_data");
    proxy->statements->Add(new VariableDeclaration(_data,
                                new MethodCall(PARCEL_TYPE, "obtain")));
    Variable* _reply = NULL;
    if (!oneway) {
        _reply = new Variable(PARCEL_TYPE, "_reply");
        proxy->statements->Add(new VariableDeclaration(_reply,
                                    new MethodCall(PARCEL_TYPE, "obtain")));
    }

    // the return value
    _result = NULL;
    if (0 != strcmp(method->type.type.data, "void")) {
        _result = new Variable(proxy->returnType, "_result",
                method->type.dimension);
        proxy->statements->Add(new VariableDeclaration(_result));
    }

    // try and finally
    TryStatement* tryStatement = new TryStatement();
    proxy->statements->Add(tryStatement);
    FinallyStatement* finallyStatement = new FinallyStatement();
    proxy->statements->Add(finallyStatement);

    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
    tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
            1, new LiteralExpression("DESCRIPTOR")));

    // the parameters
    arg = method->args;
    while (arg != NULL) {
        Type* t = NAMES.Search(arg->type.type.data);
        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
        int dir = convert_direction(arg->direction.data);
        if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
            IfStatement* checklen = new IfStatement();
            checklen->expression = new Comparison(v, "==", NULL_VALUE);
            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
                        new LiteralExpression("-1")));
            checklen->elseif = new IfStatement();
            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
                        1, new FieldVariable(v, "length")));
            tryStatement->statements->Add(checklen);
        }
        else if (dir & IN_PARAMETER) {
            generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
        }
        arg = arg->next;
    }

    // the transact call
    MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
                            new LiteralExpression("Stub." + transactCodeName),
                            _data, _reply ? _reply : NULL_VALUE,
                            new LiteralExpression(
                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
    tryStatement->statements->Add(call);

    // throw back exceptions.
    if (_reply) {
        MethodCall* ex = new MethodCall(_reply, "readException", 0);
        tryStatement->statements->Add(ex);
    }

    // returning and cleanup
    if (_reply != NULL) {
        if (_result != NULL) {
            generate_create_from_parcel(proxy->returnType,
                    tryStatement->statements, _result, _reply, &cl);
        }

        // the out/inout parameters
        arg = method->args;
        while (arg != NULL) {
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
                generate_read_from_parcel(t, tryStatement->statements,
                                            v, _reply, &cl);
            }
            arg = arg->next;
        }

        finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
    }
    finallyStatement->statements->Add(new MethodCall(_data, "recycle"));

    if (_result != NULL) {
        proxy->statements->Add(new ReturnStatement(_result));
    }
}