static void
generate_result_dispatcher_method(const method_type* method,
        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
{
    arg_type* arg;
    Method* dispatchMethod;
    Variable* dispatchParam;
    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);

    Variable* classLoader = NULL;
    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));

    // The callback method itself
    MethodCall* realCall = new MethodCall(
            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
            results_method_name(method->name.data));

    // The return value
    {
        Type* t = NAMES.Search(method->type.type.data);
        if (t != VOID_TYPE) {
            Variable* rv = new Variable(t, "rv");
            dispatchMethod->statements->Add(new VariableDeclaration(rv));
            generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
                    resultData, &classLoader);
            realCall->arguments.push_back(rv);
        }
    }

    VariableFactory stubArgs("arg");
    arg = method->args;
    while (arg != NULL) {
        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
            // Unmarshall the results
            Type* t = NAMES.Search(arg->type.type.data);
            Variable* v = stubArgs.Get(t);
            dispatchMethod->statements->Add(new VariableDeclaration(v));

            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
                    resultData, &classLoader);

            // Add the argument to the callback
            realCall->arguments.push_back(v);
        }
        arg = arg->next;
    }

    // Call the callback method
    IfStatement* ifst = new IfStatement;
        ifst->expression = new Comparison(new FieldVariable(THIS_VALUE, "callback"), "!=", NULL_VALUE);
    dispatchMethod->statements->Add(ifst);
    ifst->statements->Add(realCall);
}
예제 #2
0
bool
GenericSchedulerThread::quitThread(bool allowRestarts)
{
    if ( !isRunning() ) {
        return false;
    }

    // Disallow temporarily any thread to request a new render so that we do not end up starting the thread again
    // just after the abort
    {
        QMutexLocker k(&_imp->mustQuitMutex);
        // We already called quitThread
        if (_imp->mustQuit || !_imp->lastQuitThreadAllowedRestart) {
            return true;
        }
        _imp->mustQuit = true;
        _imp->startingThreadAllowed = false;
        _imp->lastQuitThreadAllowedRestart = allowRestarts;
    }

    if (getThreadState() == eThreadStateActive) {
        abortThreadedTask();
    }


    // Clear any task enqueued and push a fake request
    {
        QMutexLocker k(&_imp->enqueuedTasksMutex);
        _imp->enqueuedTasks.clear();
        boost::shared_ptr<GenericThreadStartArgs> stubArgs( new GenericThreadStartArgs(true) );
        _imp->enqueuedTasks.push_back(stubArgs);
    }


    // Wake-up the thread with a fake request
    {
        QMutexLocker l3(&_imp->startRequestsMutex);
        ++_imp->startRequests;
        _imp->startRequestsCond.wakeOne();
    }
#ifdef TRACE_GENERIC_SCHEDULER_THREAD
    qDebug() << QThread::currentThread() << ": Termination request on " << getThreadName().c_str();
#endif

    onQuitRequested(allowRestarts);
    return true;
}
예제 #3
0
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));
    }
}
void
DispatcherClass::AddMethod(const method_type* method)
{
    arg_type* arg;

    // The if/switch statement
    IfStatement* ifs = new IfStatement();
        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
                1, this->actionParam);
    StatementBlock* block = ifs->statements = new StatementBlock;
    if (this->dispatchIfStatement == NULL) {
        this->dispatchIfStatement = ifs;
        this->processMethod->statements->Add(dispatchIfStatement);
    } else {
        this->dispatchIfStatement->elseif = ifs;
        this->dispatchIfStatement = ifs;
    }
    
    // The call to decl (from above)
    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);

    // args
    Variable* classLoader = 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;

        // Unmarshall the parameter
        block->Add(new VariableDeclaration(v));
        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
            generate_create_from_data(t, block, arg->name.data, v,
                    this->requestData, &classLoader);
        } else {
            if (arg->type.dimension == 0) {
                block->Add(new Assignment(v, new NewExpression(v->type)));
            }
            else if (arg->type.dimension == 1) {
                generate_new_array(v->type, block, v, this->requestData);
            }
            else {
                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
                        __LINE__);
            }
        }

        // Add that parameter to the method call
        realCall->arguments.push_back(v);

        arg = arg->next;
    }

    // Add a final parameter: RpcContext. Contains data about
    // incoming request (e.g., certificate)
    realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));

    Type* returnType = NAMES.Search(method->type.type.data);
    if (returnType == EVENT_FAKE_TYPE) {
        returnType = VOID_TYPE;
    }
    
    // the real call
    bool first = true;
    Variable* _result = NULL;
    if (returnType == VOID_TYPE) {
        block->Add(realCall);
    } else {
        _result = new Variable(returnType, "_result",
                                method->type.dimension);
        block->Add(new VariableDeclaration(_result, realCall));

        // need the result RpcData
        if (first) {
            block->Add(new Assignment(this->resultData,
                        new NewExpression(RPC_DATA_TYPE)));
            first = false;
        }

        // marshall the return value
        generate_write_to_data(returnType, block,
                new StringLiteralExpression("_result"), _result, this->resultData);
    }

    // out parameters
    int 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) {
            // need the result RpcData
            if (first) {
                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
                first = false;
            }

            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
                    v, this->resultData);
        }

        arg = arg->next;
    }
}
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));
    }
}