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)); } }