diff options
author | Joe Onorato <joeo@google.com> | 2011-08-30 17:24:17 -0700 |
---|---|---|
committer | Mike Lockwood <lockwood@android.com> | 2011-10-28 10:14:49 -0400 |
commit | ae7f32e97d2ee62af7ee904849b0dd7a665ae28a (patch) | |
tree | e7226aea40a037135bd410e612a4905bca0a8810 /tools/aidl | |
parent | bc06928ef3e3c1538755b7182856665c61ad7a7e (diff) | |
download | frameworks_base-ae7f32e97d2ee62af7ee904849b0dd7a665ae28a.zip frameworks_base-ae7f32e97d2ee62af7ee904849b0dd7a665ae28a.tar.gz frameworks_base-ae7f32e97d2ee62af7ee904849b0dd7a665ae28a.tar.bz2 |
Checkpoint adding @home RPC support to aidl
Change-Id: I908950ec4892438b1d253475833e153b5a566fdc
Diffstat (limited to 'tools/aidl')
-rwxr-xr-x | tools/aidl/AST.cpp | 46 | ||||
-rwxr-xr-x | tools/aidl/AST.h | 15 | ||||
-rw-r--r-- | tools/aidl/Android.mk | 4 | ||||
-rwxr-xr-x | tools/aidl/Type.cpp | 89 | ||||
-rwxr-xr-x | tools/aidl/Type.h | 25 | ||||
-rw-r--r-- | tools/aidl/aidl.cpp | 38 | ||||
-rw-r--r-- | tools/aidl/aidl_language.h | 3 | ||||
-rw-r--r-- | tools/aidl/aidl_language_l.l | 1 | ||||
-rw-r--r-- | tools/aidl/aidl_language_y.y | 26 | ||||
-rw-r--r-- | tools/aidl/generate_java.cpp | 579 | ||||
-rw-r--r-- | tools/aidl/generate_java.h | 19 | ||||
-rw-r--r-- | tools/aidl/generate_java_binder.cpp | 559 | ||||
-rw-r--r-- | tools/aidl/generate_java_rpc.cpp | 667 |
13 files changed, 1486 insertions, 585 deletions
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp index 752ef7c..42102f8 100755 --- a/tools/aidl/AST.cpp +++ b/tools/aidl/AST.cpp @@ -111,6 +111,21 @@ LiteralExpression::Write(FILE* to) fprintf(to, "%s", this->value.c_str()); } +StringLiteralExpression::StringLiteralExpression(const string& v) + :value(v) +{ +} + +StringLiteralExpression::~StringLiteralExpression() +{ +} + +void +StringLiteralExpression::Write(FILE* to) +{ + fprintf(to, "\"%s\"", this->value.c_str()); +} + Variable::Variable() :type(NULL), name(), @@ -277,6 +292,17 @@ MethodCall::MethodCall(const string& n) { } +MethodCall::MethodCall(const string& n, int argc = 0, ...) + :obj(NULL), + clazz(NULL), + name(n) +{ + va_list args; + va_start(args, argc); + init(argc, args); + va_end(args); +} + MethodCall::MethodCall(Expression* o, const string& n) :obj(o), clazz(NULL), @@ -367,11 +393,29 @@ NewExpression::NewExpression(Type* t) { } +NewExpression::NewExpression(Type* t, int argc = 0, ...) + :type(t) +{ + va_list args; + va_start(args, argc); + init(argc, args); + va_end(args); +} + NewExpression::~NewExpression() { } void +NewExpression::init(int n, va_list args) +{ + for (int i=0; i<n; i++) { + Expression* expression = (Expression*)va_arg(args, void*); + this->arguments.push_back(expression); + } +} + +void NewExpression::Write(FILE* to) { fprintf(to, "new %s(", this->type->InstantiableName().c_str()); @@ -678,7 +722,7 @@ Method::Write(FILE* to) fprintf(to, "%s\n", this->comment.c_str()); } - WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE); + WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE); if (this->returnType != NULL) { string dim; diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h index 3156356..fe92a26 100755 --- a/tools/aidl/AST.h +++ b/tools/aidl/AST.h @@ -54,6 +54,16 @@ struct LiteralExpression : public Expression virtual void Write(FILE* to); }; +// TODO: also escape the contents. not needed for now +struct StringLiteralExpression : public Expression +{ + string value; + + StringLiteralExpression(const string& value); + virtual ~StringLiteralExpression(); + virtual void Write(FILE* to); +}; + struct Variable : public Expression { Type* type; @@ -146,6 +156,7 @@ struct MethodCall : public Expression vector<string> exceptions; MethodCall(const string& name); + MethodCall(const string& name, int argc, ...); MethodCall(Expression* obj, const string& name); MethodCall(Type* clazz, const string& name); MethodCall(Expression* obj, const string& name, int argc, ...); @@ -174,8 +185,12 @@ struct NewExpression : public Expression vector<Expression*> arguments; NewExpression(Type* type); + NewExpression(Type* type, int argc, ...); virtual ~NewExpression(); virtual void Write(FILE* to); + +private: + void init(int n, va_list args); }; struct NewArrayExpression : public Expression diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk index 2ad0728..77d46ab 100644 --- a/tools/aidl/Android.mk +++ b/tools/aidl/Android.mk @@ -17,7 +17,9 @@ LOCAL_SRC_FILES := \ search_path.cpp \ AST.cpp \ Type.cpp \ - generate_java.cpp + generate_java.cpp \ + generate_java_binder.cpp \ + generate_java_rpc.cpp LOCAL_CFLAGS := -g LOCAL_MODULE := aidl diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp index 6b69864..54690e7 100755 --- a/tools/aidl/Type.cpp +++ b/tools/aidl/Type.cpp @@ -11,6 +11,7 @@ Type* LONG_TYPE; Type* FLOAT_TYPE; Type* DOUBLE_TYPE; Type* STRING_TYPE; +Type* OBJECT_TYPE; Type* CHAR_SEQUENCE_TYPE; Type* TEXT_UTILS_TYPE; Type* REMOTE_EXCEPTION_TYPE; @@ -21,9 +22,17 @@ Type* BINDER_NATIVE_TYPE; Type* BINDER_PROXY_TYPE; Type* PARCEL_TYPE; Type* PARCELABLE_INTERFACE_TYPE; +Type* CONTEXT_TYPE; Type* MAP_TYPE; Type* LIST_TYPE; Type* CLASSLOADER_TYPE; +Type* RPC_SERVICE_BASE_TYPE; +Type* RPC_DATA_TYPE; +Type* RPC_BROKER_TYPE; +Type* RPC_ENDPOINT_INFO_TYPE; +Type* RPC_RESULT_HANDLER_TYPE; +Type* RPC_ERROR_TYPE; +Type* RPC_ERROR_LISTENER_TYPE; Expression* NULL_VALUE; Expression* THIS_VALUE; @@ -66,6 +75,10 @@ register_base_types() STRING_TYPE = new StringType(); NAMES.Add(STRING_TYPE); + OBJECT_TYPE = new Type("java.lang", "Object", + Type::BUILT_IN, false, false); + NAMES.Add(OBJECT_TYPE); + CHAR_SEQUENCE_TYPE = new CharSequenceType(); NAMES.Add(CHAR_SEQUENCE_TYPE); @@ -103,6 +116,38 @@ register_base_types() PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType(); NAMES.Add(PARCELABLE_INTERFACE_TYPE); + CONTEXT_TYPE = new Type("android.content", "Context", + Type::BUILT_IN, false, false); + NAMES.Add(CONTEXT_TYPE); + + RPC_SERVICE_BASE_TYPE = new Type("com.android.athome.service", "AndroidAtHomeService", + Type::BUILT_IN, false, false); + NAMES.Add(RPC_SERVICE_BASE_TYPE); + + RPC_DATA_TYPE = new Type("com.android.athome.rpc", "RpcData", + Type::BUILT_IN, false, false); + NAMES.Add(RPC_DATA_TYPE); + + RPC_BROKER_TYPE = new Type("com.android.athome.utils", "AndroidAtHomeBroker", + Type::BUILT_IN, false, false); + NAMES.Add(RPC_BROKER_TYPE); + + RPC_ENDPOINT_INFO_TYPE = new ParcelableType("com.android.athome.rpc", "EndpointInfo", + true, __FILE__, __LINE__); + NAMES.Add(RPC_ENDPOINT_INFO_TYPE); + + RPC_RESULT_HANDLER_TYPE = new ParcelableType("com.android.athome.rpc", "RpcResultHandler", + true, __FILE__, __LINE__); + NAMES.Add(RPC_RESULT_HANDLER_TYPE); + + RPC_ERROR_TYPE = new ParcelableType("com.android.athome.rpc", "RpcError", + true, __FILE__, __LINE__); + NAMES.Add(RPC_ERROR_TYPE); + + RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler", + Type::BUILT_IN, false, false); + NAMES.Add(RPC_ERROR_LISTENER_TYPE); + CLASSLOADER_TYPE = new ClassLoaderType(); NAMES.Add(CLASSLOADER_TYPE); @@ -244,6 +289,36 @@ Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, } void +Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, int flags) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* WriteToRpcData error " + + m_qualifiedName + " */")); +} + +void +Type::ReadFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data, + Variable** cl) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* ReadFromRpcData error " + + m_qualifiedName + " */")); +} + +void +Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data, + Variable** cl) +{ + fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn", + __FILE__, __LINE__, m_qualifiedName.c_str()); + addTo->Add(new LiteralExpression("/* ReadFromRpcData error " + + m_qualifiedName + " */")); +} + +void Type::SetQualifiedName(const string& qualified) { m_qualifiedName = qualified; @@ -458,6 +533,20 @@ StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* pa addTo->Add(new MethodCall(parcel, "readStringArray", 1, v)); } +void +StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, int flags) +{ + addTo->Add(new MethodCall(data, "putString", 2, k, v)); +} + +void +StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, Variable**) +{ + addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k))); +} + // ================================================================ CharSequenceType::CharSequenceType() diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h index 662e3a2..1015dcf 100755 --- a/tools/aidl/Type.h +++ b/tools/aidl/Type.h @@ -59,6 +59,14 @@ public: virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl); + virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, int flags); + virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, Variable** cl); + virtual void ReadFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, Variable** cl); + + protected: void SetQualifiedName(const string& qualified); Expression* BuildWriteToParcelFlags(int flags); @@ -169,6 +177,11 @@ public: Variable* parcel, Variable** cl); virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl); + + virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, int flags); + virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, + Variable* data, Variable** cl); }; class CharSequenceType : public Type @@ -438,11 +451,13 @@ extern Namespace NAMES; extern Type* VOID_TYPE; extern Type* BOOLEAN_TYPE; +extern Type* BYTE_TYPE; extern Type* CHAR_TYPE; extern Type* INT_TYPE; extern Type* LONG_TYPE; extern Type* FLOAT_TYPE; extern Type* DOUBLE_TYPE; +extern Type* OBJECT_TYPE; extern Type* STRING_TYPE; extern Type* CHAR_SEQUENCE_TYPE; extern Type* TEXT_UTILS_TYPE; @@ -455,6 +470,16 @@ extern Type* BINDER_PROXY_TYPE; extern Type* PARCEL_TYPE; extern Type* PARCELABLE_INTERFACE_TYPE; +extern Type* CONTEXT_TYPE; + +extern Type* RPC_SERVICE_BASE_TYPE; +extern Type* RPC_DATA_TYPE; +extern Type* RPC_BROKER_TYPE; +extern Type* RPC_ENDPOINT_INFO_TYPE; +extern Type* RPC_RESULT_HANDLER_TYPE; +extern Type* RPC_ERROR_TYPE; +extern Type* RPC_ERROR_LISTENER_TYPE; + extern Expression* NULL_VALUE; extern Expression* THIS_VALUE; extern Expression* SUPER_VALUE; diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp index fb4067a..78404cb 100644 --- a/tools/aidl/aidl.cpp +++ b/tools/aidl/aidl.cpp @@ -29,7 +29,7 @@ static void test_document(document_item_type* d) { while (d) { - if (d->item_type == INTERFACE_TYPE) { + if (d->item_type == INTERFACE_TYPE_BINDER) { interface_type* c = (interface_type*)d; printf("interface %s %s {\n", c->package, c->name.data); interface_item_type *q = (interface_item_type*)c->interface_items; @@ -242,7 +242,8 @@ check_filenames(const char* filename, document_item_type* items) parcelable_type* p = (parcelable_type*)items; err |= check_filename(filename, p->package, &p->name); } - else if (items->item_type == INTERFACE_TYPE) { + else if (items->item_type == INTERFACE_TYPE_BINDER + || items->item_type == INTERFACE_TYPE_RPC) { interface_type* c = (interface_type*)items; err |= check_filename(filename, c->package, &c->name); } @@ -295,7 +296,8 @@ gather_types(const char* filename, document_item_type* items) type = new ParcelableType(p->package ? p->package : "", p->name.data, false, filename, p->name.lineno); } - else if (items->item_type == INTERFACE_TYPE) { + else if (items->item_type == INTERFACE_TYPE_BINDER + || items->item_type == INTERFACE_TYPE_RPC) { interface_type* c = (interface_type*)items; type = new InterfaceType(c->package ? c->package : "", c->name.data, false, c->oneway, @@ -310,7 +312,7 @@ gather_types(const char* filename, document_item_type* items) if (old == NULL) { NAMES.Add(type); - if (items->item_type == INTERFACE_TYPE) { + if (items->item_type == INTERFACE_TYPE_BINDER) { // for interfaces, also add the stub and proxy types, we don't // bother checking these for duplicates, because the parser // won't let us do it. @@ -330,6 +332,19 @@ gather_types(const char* filename, document_item_type* items) filename, c->name.lineno); NAMES.Add(proxy); } + else if (items->item_type == INTERFACE_TYPE_RPC) { + // for interfaces, also add the service base type, we don't + // bother checking these for duplicates, because the parser + // won't let us do it. + interface_type* c = (interface_type*)items; + + string name = c->name.data; + name += ".ServiceBase"; + Type* base = new Type(c->package ? c->package : "", + name, Type::GENERATED, false, false, + filename, c->name.lineno); + NAMES.Add(base); + } } else { if (old->Kind() == Type::BUILT_IN) { fprintf(stderr, "%s:%d attempt to redefine built in class %s\n", @@ -498,7 +513,7 @@ check_types(const char* filename, document_item_type* items) int err = 0; while (items) { // (nothing to check for PARCELABLE_TYPE) - if (items->item_type == INTERFACE_TYPE) { + if (items->item_type == INTERFACE_TYPE_BINDER) { map<string,method_type*> methodNames; interface_type* c = (interface_type*)items; @@ -544,7 +559,10 @@ exactly_one_interface(const char* filename, const document_item_type* items, con const document_item_type* next = items->next; if (items->next != NULL) { int lineno = -1; - if (next->item_type == INTERFACE_TYPE) { + if (next->item_type == INTERFACE_TYPE_BINDER) { + lineno = ((interface_type*)next)->interface_token.lineno; + } + else if (next->item_type == INTERFACE_TYPE_RPC) { lineno = ((interface_type*)next)->interface_token.lineno; } else if (next->item_type == PARCELABLE_TYPE) { @@ -598,7 +616,7 @@ generate_dep_file(const Options& options, const document_item_type* items) slash = ""; } - if (items->item_type == INTERFACE_TYPE) { + if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) { fprintf(to, "%s: \\\n", options.outputFileName.c_str()); } else { // parcelable: there's no output file. @@ -658,7 +676,7 @@ static string generate_outputFileName(const Options& options, const document_item_type* items) { // items has already been checked to have only one interface. - if (items->item_type == INTERFACE_TYPE) { + if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) { interface_type* type = (interface_type*)items; return generate_outputFileName2(options, type->name, type->package); @@ -751,7 +769,7 @@ parse_preprocessed_file(const string& filename) interface_type* iface = (interface_type*)malloc( sizeof(interface_type)); memset(iface, 0, sizeof(interface_type)); - iface->document_item.item_type = INTERFACE_TYPE; + iface->document_item.item_type = INTERFACE_TYPE_BINDER; iface->interface_token.lineno = lineno; iface->interface_token.data = strdup(type); iface->package = packagename ? strdup(packagename) : NULL; @@ -995,5 +1013,3 @@ main(int argc, const char **argv) fprintf(stderr, "aidl: internal error\n"); return 1; } - - diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h index 9ca5deb..985f646 100644 --- a/tools/aidl/aidl_language.h +++ b/tools/aidl/aidl_language.h @@ -64,7 +64,8 @@ typedef struct method_type { enum { PARCELABLE_TYPE = 12, - INTERFACE_TYPE + INTERFACE_TYPE_BINDER, + INTERFACE_TYPE_RPC }; typedef struct document_item_type { diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l index 567b1cf..8092366 100644 --- a/tools/aidl/aidl_language_l.l +++ b/tools/aidl/aidl_language_l.l @@ -81,6 +81,7 @@ brackets \[{whitespace}?\] /* keywords */ parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; } interface { SET_BUFFER(INTERFACE); return INTERFACE; } +rpc { SET_BUFFER(INTERFACE); return RPC; } in { SET_BUFFER(IN); return IN; } out { SET_BUFFER(OUT); return OUT; } inout { SET_BUFFER(INOUT); return INOUT; } diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y index 3d65f17..965d936 100644 --- a/tools/aidl/aidl_language_y.y +++ b/tools/aidl/aidl_language_y.y @@ -19,6 +19,7 @@ static int count_brackets(const char*); %token ARRAY %token PARCELABLE %token INTERFACE +%token RPC %token IN %token OUT %token INOUT @@ -102,6 +103,8 @@ parcelable_decl: interface_header: INTERFACE { interface_type* c = (interface_type*)malloc(sizeof(interface_type)); + c->document_item.item_type = INTERFACE_TYPE_BINDER; + c->document_item.next = NULL; c->interface_token = $1.buffer; c->oneway = false; memset(&c->oneway_token, 0, sizeof(buffer_type)); @@ -110,19 +113,34 @@ interface_header: } | ONEWAY INTERFACE { interface_type* c = (interface_type*)malloc(sizeof(interface_type)); + c->document_item.item_type = INTERFACE_TYPE_BINDER; + c->document_item.next = NULL; c->interface_token = $2.buffer; c->oneway = true; c->oneway_token = $1.buffer; c->comments_token = &c->oneway_token; $$.interface_obj = c; } + | RPC { + interface_type* c = (interface_type*)malloc(sizeof(interface_type)); + c->document_item.item_type = INTERFACE_TYPE_RPC; + c->document_item.next = NULL; + c->interface_token = $1.buffer; + c->oneway = false; + memset(&c->oneway_token, 0, sizeof(buffer_type)); + c->comments_token = &c->interface_token; + $$.interface_obj = c; + } + ; + +interface_keywords: + INTERFACE + | RPC ; interface_decl: interface_header IDENTIFIER '{' interface_items '}' { interface_type* c = $1.interface_obj; - c->document_item.item_type = INTERFACE_TYPE; - c->document_item.next = NULL; c->name = $2.buffer; c->package = g_currentPackage ? strdup(g_currentPackage) : NULL; c->open_brace_token = $3.buffer; @@ -130,12 +148,12 @@ interface_decl: c->close_brace_token = $5.buffer; $$.interface_obj = c; } - | INTERFACE error '{' interface_items '}' { + | interface_keywords error '{' interface_items '}' { fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n", g_currentFilename, $2.buffer.lineno, $2.buffer.data); $$.document_item = NULL; } - | INTERFACE error '}' { + | interface_keywords error '}' { fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n", g_currentFilename, $2.buffer.lineno, $2.buffer.data); $$.document_item = NULL; diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp index 83e3bbc..9e57407 100644 --- a/tools/aidl/generate_java.cpp +++ b/tools/aidl/generate_java.cpp @@ -1,5 +1,4 @@ #include "generate_java.h" -#include "AST.h" #include "Type.h" #include <string.h> #include <stdio.h> @@ -7,18 +6,6 @@ #include <string.h> // ================================================= -class VariableFactory -{ -public: - VariableFactory(const string& base); // base must be short - Variable* Get(Type* type); - Variable* Get(int index); -private: - vector<Variable*> m_vars; - string m_base; - int m_index; -}; - VariableFactory::VariableFactory(const string& base) :m_base(base), m_index(0) @@ -43,195 +30,7 @@ VariableFactory::Get(int index) } // ================================================= -class StubClass : public Class -{ -public: - StubClass(Type* type, Type* interfaceType); - virtual ~StubClass(); - - Variable* transact_code; - Variable* transact_data; - Variable* transact_reply; - Variable* transact_flags; - SwitchStatement* transact_switch; -private: - void make_as_interface(Type* interfaceType); -}; - -StubClass::StubClass(Type* type, Type* interfaceType) - :Class() -{ - this->comment = "/** Local-side IPC implementation stub class. */"; - this->modifiers = PUBLIC | ABSTRACT | STATIC; - this->what = Class::CLASS; - this->type = type; - this->extends = BINDER_NATIVE_TYPE; - this->interfaces.push_back(interfaceType); - - // descriptor - Field* descriptor = new Field(STATIC | FINAL | PRIVATE, - new Variable(STRING_TYPE, "DESCRIPTOR")); - descriptor->value = "\"" + interfaceType->QualifiedName() + "\""; - this->elements.push_back(descriptor); - - // ctor - Method* ctor = new Method; - ctor->modifiers = PUBLIC; - ctor->comment = "/** Construct the stub at attach it to the " - "interface. */"; - ctor->name = "Stub"; - ctor->statements = new StatementBlock; - MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface", - 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR")); - ctor->statements->Add(attach); - this->elements.push_back(ctor); - - // asInterface - make_as_interface(interfaceType); - - // asBinder - Method* asBinder = new Method; - asBinder->modifiers = PUBLIC; - asBinder->returnType = IBINDER_TYPE; - asBinder->name = "asBinder"; - asBinder->statements = new StatementBlock; - asBinder->statements->Add(new ReturnStatement(THIS_VALUE)); - this->elements.push_back(asBinder); - - // onTransact - this->transact_code = new Variable(INT_TYPE, "code"); - this->transact_data = new Variable(PARCEL_TYPE, "data"); - this->transact_reply = new Variable(PARCEL_TYPE, "reply"); - this->transact_flags = new Variable(INT_TYPE, "flags"); - Method* onTransact = new Method; - onTransact->modifiers = PUBLIC | OVERRIDE; - onTransact->returnType = BOOLEAN_TYPE; - onTransact->name = "onTransact"; - onTransact->parameters.push_back(this->transact_code); - onTransact->parameters.push_back(this->transact_data); - onTransact->parameters.push_back(this->transact_reply); - onTransact->parameters.push_back(this->transact_flags); - onTransact->statements = new StatementBlock; - onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE); - this->elements.push_back(onTransact); - this->transact_switch = new SwitchStatement(this->transact_code); - - onTransact->statements->Add(this->transact_switch); - MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4, - this->transact_code, this->transact_data, - this->transact_reply, this->transact_flags); - onTransact->statements->Add(new ReturnStatement(superCall)); -} - -StubClass::~StubClass() -{ -} - -void -StubClass::make_as_interface(Type *interfaceType) -{ - Variable* obj = new Variable(IBINDER_TYPE, "obj"); - - Method* m = new Method; - m->comment = "/**\n * Cast an IBinder object into an "; - m->comment += interfaceType->QualifiedName(); - m->comment += " interface,\n"; - m->comment += " * generating a proxy if needed.\n */"; - m->modifiers = PUBLIC | STATIC; - m->returnType = interfaceType; - m->name = "asInterface"; - m->parameters.push_back(obj); - m->statements = new StatementBlock; - - IfStatement* ifstatement = new IfStatement(); - ifstatement->expression = new Comparison(obj, "==", NULL_VALUE); - ifstatement->statements = new StatementBlock; - ifstatement->statements->Add(new ReturnStatement(NULL_VALUE)); - m->statements->Add(ifstatement); - - // IInterface iin = obj.queryLocalInterface(DESCRIPTOR) - MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface"); - queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR")); - IInterfaceType* iinType = new IInterfaceType(); - Variable *iin = new Variable(iinType, "iin"); - VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType); - m->statements->Add(iinVd); - - // Ensure the instance type of the local object is as expected. - // One scenario where this is needed is if another package (with a - // different class loader) runs in the same process as the service. - - // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin; - Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE); - Comparison* instOfCheck = new Comparison(iin, " instanceof ", - new LiteralExpression(interfaceType->QualifiedName())); - IfStatement* instOfStatement = new IfStatement(); - instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck); - instOfStatement->statements = new StatementBlock; - instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin))); - m->statements->Add(instOfStatement); - - string proxyType = interfaceType->QualifiedName(); - proxyType += ".Stub.Proxy"; - NewExpression* ne = new NewExpression(NAMES.Find(proxyType)); - ne->arguments.push_back(obj); - m->statements->Add(new ReturnStatement(ne)); - - this->elements.push_back(m); -} - - - -// ================================================= -class ProxyClass : public Class -{ -public: - ProxyClass(Type* type, InterfaceType* interfaceType); - virtual ~ProxyClass(); - - Variable* mRemote; - bool mOneWay; -}; - -ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType) - :Class() -{ - this->modifiers = PRIVATE | STATIC; - this->what = Class::CLASS; - this->type = type; - this->interfaces.push_back(interfaceType); - - mOneWay = interfaceType->OneWay(); - - // IBinder mRemote - mRemote = new Variable(IBINDER_TYPE, "mRemote"); - this->elements.push_back(new Field(PRIVATE, mRemote)); - - // Proxy() - Variable* remote = new Variable(IBINDER_TYPE, "remote"); - Method* ctor = new Method; - ctor->name = "Proxy"; - ctor->statements = new StatementBlock; - ctor->parameters.push_back(remote); - ctor->statements->Add(new Assignment(mRemote, remote)); - this->elements.push_back(ctor); - - // IBinder asBinder() - Method* asBinder = new Method; - asBinder->modifiers = PUBLIC; - asBinder->returnType = IBINDER_TYPE; - asBinder->name = "asBinder"; - asBinder->statements = new StatementBlock; - asBinder->statements->Add(new ReturnStatement(mRemote)); - this->elements.push_back(asBinder); -} - -ProxyClass::~ProxyClass() -{ -} - -// ================================================= -static string +string gather_comments(extra_text_type* extra) { string s; @@ -249,7 +48,7 @@ gather_comments(extra_text_type* extra) return s; } -static string +string append(const char* a, const char* b) { string s = a; @@ -257,379 +56,25 @@ append(const char* a, const char* b) return s; } -static void -generate_new_array(Type* t, StatementBlock* addTo, Variable* v, - Variable* parcel) -{ - Variable* len = new Variable(INT_TYPE, v->name + "_length"); - addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt"))); - IfStatement* lencheck = new IfStatement(); - lencheck->expression = new Comparison(len, "<", new LiteralExpression("0")); - lencheck->statements->Add(new Assignment(v, NULL_VALUE)); - lencheck->elseif = new IfStatement(); - lencheck->elseif->statements->Add(new Assignment(v, - new NewArrayExpression(t, len))); - addTo->Add(lencheck); -} - -static void -generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v, - Variable* parcel, int flags) -{ - if (v->dimension == 0) { - t->WriteToParcel(addTo, v, parcel, flags); - } - if (v->dimension == 1) { - t->WriteArrayToParcel(addTo, v, parcel, flags); - } -} - -static void -generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v, - Variable* parcel, Variable** cl) +// ================================================= +int +generate_java(const string& filename, const string& originalSrc, + interface_type* iface) { - if (v->dimension == 0) { - t->CreateFromParcel(addTo, v, parcel, cl); - } - if (v->dimension == 1) { - t->CreateArrayFromParcel(addTo, v, parcel, cl); - } -} + Class* cl; -static void -generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v, - Variable* parcel, Variable** cl) -{ - if (v->dimension == 0) { - t->ReadFromParcel(addTo, v, parcel, cl); - } - if (v->dimension == 1) { - t->ReadArrayFromParcel(addTo, v, parcel, cl); + if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) { + cl = generate_binder_interface_class(iface); } -} - - -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; + else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) { + cl = generate_rpc_interface_class(iface); } - 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)); - } -} - -static void -generate_interface_descriptors(StubClass* stub, ProxyClass* proxy) -{ - // the interface descriptor transaction handler - Case* c = new Case("INTERFACE_TRANSACTION"); - c->statements->Add(new MethodCall(stub->transact_reply, "writeString", - 1, new LiteralExpression("DESCRIPTOR"))); - c->statements->Add(new ReturnStatement(TRUE_VALUE)); - stub->transact_switch->cases.push_back(c); - - // and the proxy-side method returning the descriptor directly - Method* getDesc = new Method; - getDesc->modifiers = PUBLIC; - getDesc->returnType = STRING_TYPE; - getDesc->returnTypeDimension = 0; - getDesc->name = "getInterfaceDescriptor"; - getDesc->statements = new StatementBlock; - getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); - proxy->elements.push_back(getDesc); -} - -static Class* -generate_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) { - generate_method((method_type*)item, interface, stub, proxy, index); - } - item = item->next; - index++; - } - - return interface; -} - -int -generate_java(const string& filename, const string& originalSrc, - interface_type* iface) -{ Document* document = new Document; document->comment = ""; if (iface->package) document->package = iface->package; document->originalSrc = originalSrc; - document->classes.push_back(generate_interface_class(iface)); + document->classes.push_back(cl); // printf("outputting... filename=%s\n", filename.c_str()); FILE* to; diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h index 203fe23..4bfcfeb 100644 --- a/tools/aidl/generate_java.h +++ b/tools/aidl/generate_java.h @@ -2,6 +2,7 @@ #define GENERATE_JAVA_H #include "aidl_language.h" +#include "AST.h" #include <string> @@ -10,5 +11,23 @@ using namespace std; int generate_java(const string& filename, const string& originalSrc, interface_type* iface); +Class* generate_binder_interface_class(const interface_type* iface); +Class* generate_rpc_interface_class(const interface_type* iface); + +string gather_comments(extra_text_type* extra); +string append(const char* a, const char* b); + +class VariableFactory +{ +public: + VariableFactory(const string& base); // base must be short + Variable* Get(Type* type); + Variable* Get(int index); +private: + vector<Variable*> m_vars; + string m_base; + int m_index; +}; + #endif // GENERATE_JAVA_H diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp new file mode 100644 index 0000000..2e459a8 --- /dev/null +++ b/tools/aidl/generate_java_binder.cpp @@ -0,0 +1,559 @@ +#include "generate_java.h" +#include "Type.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// ================================================= +class StubClass : public Class +{ +public: + StubClass(Type* type, Type* interfaceType); + virtual ~StubClass(); + + Variable* transact_code; + Variable* transact_data; + Variable* transact_reply; + Variable* transact_flags; + SwitchStatement* transact_switch; +private: + void make_as_interface(Type* interfaceType); +}; + +StubClass::StubClass(Type* type, Type* interfaceType) + :Class() +{ + this->comment = "/** Local-side IPC implementation stub class. */"; + this->modifiers = PUBLIC | ABSTRACT | STATIC; + this->what = Class::CLASS; + this->type = type; + this->extends = BINDER_NATIVE_TYPE; + this->interfaces.push_back(interfaceType); + + // descriptor + Field* descriptor = new Field(STATIC | FINAL | PRIVATE, + new Variable(STRING_TYPE, "DESCRIPTOR")); + descriptor->value = "\"" + interfaceType->QualifiedName() + "\""; + this->elements.push_back(descriptor); + + // ctor + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->comment = "/** Construct the stub at attach it to the " + "interface. */"; + ctor->name = "Stub"; + ctor->statements = new StatementBlock; + MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface", + 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR")); + ctor->statements->Add(attach); + this->elements.push_back(ctor); + + // asInterface + make_as_interface(interfaceType); + + // asBinder + Method* asBinder = new Method; + asBinder->modifiers = PUBLIC; + asBinder->returnType = IBINDER_TYPE; + asBinder->name = "asBinder"; + asBinder->statements = new StatementBlock; + asBinder->statements->Add(new ReturnStatement(THIS_VALUE)); + this->elements.push_back(asBinder); + + // onTransact + this->transact_code = new Variable(INT_TYPE, "code"); + this->transact_data = new Variable(PARCEL_TYPE, "data"); + this->transact_reply = new Variable(PARCEL_TYPE, "reply"); + this->transact_flags = new Variable(INT_TYPE, "flags"); + Method* onTransact = new Method; + onTransact->modifiers = PUBLIC | OVERRIDE; + onTransact->returnType = BOOLEAN_TYPE; + onTransact->name = "onTransact"; + onTransact->parameters.push_back(this->transact_code); + onTransact->parameters.push_back(this->transact_data); + onTransact->parameters.push_back(this->transact_reply); + onTransact->parameters.push_back(this->transact_flags); + onTransact->statements = new StatementBlock; + onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE); + this->elements.push_back(onTransact); + this->transact_switch = new SwitchStatement(this->transact_code); + + onTransact->statements->Add(this->transact_switch); + MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4, + this->transact_code, this->transact_data, + this->transact_reply, this->transact_flags); + onTransact->statements->Add(new ReturnStatement(superCall)); +} + +StubClass::~StubClass() +{ +} + +void +StubClass::make_as_interface(Type *interfaceType) +{ + Variable* obj = new Variable(IBINDER_TYPE, "obj"); + + Method* m = new Method; + m->comment = "/**\n * Cast an IBinder object into an "; + m->comment += interfaceType->QualifiedName(); + m->comment += " interface,\n"; + m->comment += " * generating a proxy if needed.\n */"; + m->modifiers = PUBLIC | STATIC; + m->returnType = interfaceType; + m->name = "asInterface"; + m->parameters.push_back(obj); + m->statements = new StatementBlock; + + IfStatement* ifstatement = new IfStatement(); + ifstatement->expression = new Comparison(obj, "==", NULL_VALUE); + ifstatement->statements = new StatementBlock; + ifstatement->statements->Add(new ReturnStatement(NULL_VALUE)); + m->statements->Add(ifstatement); + + // IInterface iin = obj.queryLocalInterface(DESCRIPTOR) + MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface"); + queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR")); + IInterfaceType* iinType = new IInterfaceType(); + Variable *iin = new Variable(iinType, "iin"); + VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType); + m->statements->Add(iinVd); + + // Ensure the instance type of the local object is as expected. + // One scenario where this is needed is if another package (with a + // different class loader) runs in the same process as the service. + + // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin; + Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE); + Comparison* instOfCheck = new Comparison(iin, " instanceof ", + new LiteralExpression(interfaceType->QualifiedName())); + IfStatement* instOfStatement = new IfStatement(); + instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck); + instOfStatement->statements = new StatementBlock; + instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin))); + m->statements->Add(instOfStatement); + + string proxyType = interfaceType->QualifiedName(); + proxyType += ".Stub.Proxy"; + NewExpression* ne = new NewExpression(NAMES.Find(proxyType)); + ne->arguments.push_back(obj); + m->statements->Add(new ReturnStatement(ne)); + + this->elements.push_back(m); +} + + + +// ================================================= +class ProxyClass : public Class +{ +public: + ProxyClass(Type* type, InterfaceType* interfaceType); + virtual ~ProxyClass(); + + Variable* mRemote; + bool mOneWay; +}; + +ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType) + :Class() +{ + this->modifiers = PRIVATE | STATIC; + this->what = Class::CLASS; + this->type = type; + this->interfaces.push_back(interfaceType); + + mOneWay = interfaceType->OneWay(); + + // IBinder mRemote + mRemote = new Variable(IBINDER_TYPE, "mRemote"); + this->elements.push_back(new Field(PRIVATE, mRemote)); + + // Proxy() + Variable* remote = new Variable(IBINDER_TYPE, "remote"); + Method* ctor = new Method; + ctor->name = "Proxy"; + ctor->statements = new StatementBlock; + ctor->parameters.push_back(remote); + ctor->statements->Add(new Assignment(mRemote, remote)); + this->elements.push_back(ctor); + + // IBinder asBinder() + Method* asBinder = new Method; + asBinder->modifiers = PUBLIC; + asBinder->returnType = IBINDER_TYPE; + asBinder->name = "asBinder"; + asBinder->statements = new StatementBlock; + asBinder->statements->Add(new ReturnStatement(mRemote)); + this->elements.push_back(asBinder); +} + +ProxyClass::~ProxyClass() +{ +} + +// ================================================= +static void +generate_new_array(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel) +{ + Variable* len = new Variable(INT_TYPE, v->name + "_length"); + addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt"))); + IfStatement* lencheck = new IfStatement(); + lencheck->expression = new Comparison(len, "<", new LiteralExpression("0")); + lencheck->statements->Add(new Assignment(v, NULL_VALUE)); + lencheck->elseif = new IfStatement(); + lencheck->elseif->statements->Add(new Assignment(v, + new NewArrayExpression(t, len))); + addTo->Add(lencheck); +} + +static void +generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel, int flags) +{ + if (v->dimension == 0) { + t->WriteToParcel(addTo, v, parcel, flags); + } + if (v->dimension == 1) { + t->WriteArrayToParcel(addTo, v, parcel, flags); + } +} + +static void +generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel, Variable** cl) +{ + if (v->dimension == 0) { + t->CreateFromParcel(addTo, v, parcel, cl); + } + if (v->dimension == 1) { + t->CreateArrayFromParcel(addTo, v, parcel, cl); + } +} + +static void +generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v, + Variable* parcel, Variable** cl) +{ + if (v->dimension == 0) { + t->ReadFromParcel(addTo, v, parcel, cl); + } + if (v->dimension == 1) { + t->ReadArrayFromParcel(addTo, v, parcel, cl); + } +} + + +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)); + } +} + +static void +generate_interface_descriptors(StubClass* stub, ProxyClass* proxy) +{ + // the interface descriptor transaction handler + Case* c = new Case("INTERFACE_TRANSACTION"); + c->statements->Add(new MethodCall(stub->transact_reply, "writeString", + 1, new LiteralExpression("DESCRIPTOR"))); + c->statements->Add(new ReturnStatement(TRUE_VALUE)); + stub->transact_switch->cases.push_back(c); + + // and the proxy-side method returning the descriptor directly + Method* getDesc = new Method; + getDesc->modifiers = PUBLIC; + getDesc->returnType = STRING_TYPE; + getDesc->returnTypeDimension = 0; + getDesc->name = "getInterfaceDescriptor"; + getDesc->statements = new StatementBlock; + getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); + proxy->elements.push_back(getDesc); +} + +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) { + generate_method((method_type*)item, interface, stub, proxy, index); + } + item = item->next; + index++; + } + + return interface; +} + diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp new file mode 100644 index 0000000..f7489b3 --- /dev/null +++ b/tools/aidl/generate_java_rpc.cpp @@ -0,0 +1,667 @@ +#include "generate_java.h" +#include "Type.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +Type* SERVICE_CONTAINER_TYPE = new Type("com.android.athome.service", + "AndroidAtHomeServiceContainer", Type::BUILT_IN, false, false); + +static string +format_int(int n) +{ + char str[20]; + sprintf(str, "%d", n); + return string(str); +} + +static string +class_name_leaf(const string& str) +{ + string::size_type pos = str.rfind('.'); + if (pos == string::npos) { + return str; + } else { + return string(str, pos+1); + } +} + +// ================================================= +class RpcProxyClass : public Class +{ +public: + RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType); + virtual ~RpcProxyClass(); + + Variable* endpoint; + Variable* context; + +private: + void generate_ctor(); +}; + +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; + + // context + this->context = new Variable(CONTEXT_TYPE, "_context"); + this->elements.push_back(new Field(PRIVATE, this->context)); + // endpoint + this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint"); + this->elements.push_back(new Field(PRIVATE, this->endpoint)); + + // methods + generate_ctor(); +} + +RpcProxyClass::~RpcProxyClass() +{ +} + +void +RpcProxyClass::generate_ctor() +{ + Variable* context = new Variable(CONTEXT_TYPE, "context"); + Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint"); + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->name = this->type->Name(); + ctor->statements = new StatementBlock; + ctor->parameters.push_back(context); + ctor->parameters.push_back(endpoint); + this->elements.push_back(ctor); + + ctor->statements->Add(new Assignment(this->context, context)); + ctor->statements->Add(new Assignment(this->endpoint, endpoint)); +} + +// ================================================= +class ServiceBaseClass : public Class +{ +public: + ServiceBaseClass(const interface_type* iface); + virtual ~ServiceBaseClass(); + + void AddMethod(const string& methodName, StatementBlock** statements); + void DoneWithMethods(); + + bool needed; + Method* processMethod; + Variable* actionParam; + Variable* errorParam; + Variable* requestData; + Variable* resultData; + IfStatement* dispatchIfStatement; + +private: + void generate_ctor(); + void generate_process(); +}; + +ServiceBaseClass::ServiceBaseClass(const interface_type* iface) + :Class(), + needed(false), + dispatchIfStatement(NULL) +{ + this->comment = "/** Extend this to implement a link service. */"; + this->modifiers = STATIC | PUBLIC | ABSTRACT; + this->what = Class::CLASS; + this->type = NAMES.Find(iface->package, append(iface->name.data, ".ServiceBase").c_str()); + this->extends = RPC_SERVICE_BASE_TYPE; + + // methods + generate_ctor(); + generate_process(); +} + +ServiceBaseClass::~ServiceBaseClass() +{ +} + +void +ServiceBaseClass::generate_ctor() +{ + Variable* container = new Variable(SERVICE_CONTAINER_TYPE, "container"); + Variable* name = new Variable(STRING_TYPE, "name"); + Variable* type = new Variable(STRING_TYPE, "type"); + Variable* version = new Variable(INT_TYPE, "version"); + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->name = class_name_leaf(this->type->Name()); + ctor->statements = new StatementBlock; + ctor->parameters.push_back(container); + ctor->parameters.push_back(name); + ctor->parameters.push_back(type); + ctor->parameters.push_back(version); + this->elements.push_back(ctor); + + ctor->statements->Add(new MethodCall("super", 4, container, name, type, version)); +} + +void +ServiceBaseClass::generate_process() +{ + // byte[] process(String action, byte[] params, RpcError status) + this->processMethod = new Method; + this->processMethod->modifiers = PUBLIC; + this->processMethod->returnType = BYTE_TYPE; + this->processMethod->returnTypeDimension = 1; + this->processMethod->name = "process"; + this->processMethod->statements = new StatementBlock; + this->elements.push_back(this->processMethod); + + this->actionParam = new Variable(STRING_TYPE, "action"); + this->processMethod->parameters.push_back(this->actionParam); + + Variable* requestParam = new Variable(BYTE_TYPE, "requestParam", 1); + this->processMethod->parameters.push_back(requestParam); + + this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0); + this->processMethod->parameters.push_back(this->errorParam); + + this->requestData = new Variable(RPC_DATA_TYPE, "request"); + this->processMethod->statements->Add(new VariableDeclaration(requestData, + new NewExpression(RPC_DATA_TYPE, 1, requestParam))); + + this->resultData = new Variable(RPC_DATA_TYPE, "response"); + this->processMethod->statements->Add(new VariableDeclaration(this->resultData, + NULL_VALUE)); +} + +void +ServiceBaseClass::AddMethod(const string& methodName, StatementBlock** statements) +{ + IfStatement* ifs = new IfStatement(); + ifs->expression = new MethodCall(new StringLiteralExpression(methodName), "equals", 1, + this->actionParam); + ifs->statements = *statements = new StatementBlock; + if (this->dispatchIfStatement == NULL) { + this->dispatchIfStatement = ifs; + this->processMethod->statements->Add(dispatchIfStatement); + } else { + this->dispatchIfStatement->elseif = ifs; + this->dispatchIfStatement = ifs; + } +} + +void +ServiceBaseClass::DoneWithMethods() +{ + IfStatement* s = new IfStatement; + s->statements = new StatementBlock; + this->processMethod->statements->Add(s); + s->expression = new Comparison(this->resultData, "!=", NULL_VALUE); + s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize"))); + s->elseif = new IfStatement; + s = s->elseif; + s->statements->Add(new ReturnStatement(NULL_VALUE)); +} + +// ================================================= +class ResultDispatcherClass : public Class +{ +public: + ResultDispatcherClass(); + virtual ~ResultDispatcherClass(); + + void AddMethod(int index, const string& name, Method** method, Variable** param); + + bool needed; + Variable* methodId; + Variable* callback; + Method* onResultMethod; + Variable* resultParam; + SwitchStatement* methodSwitch; + +private: + void generate_ctor(); + void generate_onResult(); +}; + +ResultDispatcherClass::ResultDispatcherClass() + :Class(), + needed(false) +{ + this->modifiers = PRIVATE | FINAL; + this->what = Class::CLASS; + this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false); + this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE); + + // methodId + this->methodId = new Variable(INT_TYPE, "methodId"); + this->elements.push_back(new Field(PRIVATE, this->methodId)); + this->callback = new Variable(OBJECT_TYPE, "callback"); + this->elements.push_back(new Field(PRIVATE, this->callback)); + + // methods + generate_ctor(); + generate_onResult(); +} + +ResultDispatcherClass::~ResultDispatcherClass() +{ +} + +void +ResultDispatcherClass::generate_ctor() +{ + Variable* methodIdParam = new Variable(INT_TYPE, "methId"); + Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj"); + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->name = this->type->Name(); + ctor->statements = new StatementBlock; + ctor->parameters.push_back(methodIdParam); + ctor->parameters.push_back(callbackParam); + this->elements.push_back(ctor); + + ctor->statements->Add(new Assignment(this->methodId, methodIdParam)); + ctor->statements->Add(new Assignment(this->callback, callbackParam)); +} + +void +ResultDispatcherClass::generate_onResult() +{ + this->onResultMethod = new Method; + this->onResultMethod->modifiers = PUBLIC; + this->onResultMethod->returnType = VOID_TYPE; + this->onResultMethod->returnTypeDimension = 0; + this->onResultMethod->name = "onResult"; + this->onResultMethod->statements = new StatementBlock; + this->elements.push_back(this->onResultMethod); + + this->resultParam = new Variable(BYTE_TYPE, "result", 1); + this->onResultMethod->parameters.push_back(this->resultParam); + + this->methodSwitch = new SwitchStatement(this->methodId); + this->onResultMethod->statements->Add(this->methodSwitch); +} + +void +ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param) +{ + Method* m = new Method; + m->modifiers = PUBLIC; + m->returnType = VOID_TYPE; + m->returnTypeDimension = 0; + m->name = name; + m->statements = new StatementBlock; + *param = new Variable(BYTE_TYPE, "result", 1); + m->parameters.push_back(*param); + this->elements.push_back(m); + *method = m; + + Case* c = new Case(format_int(index)); + c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam)); + + this->methodSwitch->cases.push_back(c); +} + +// ================================================= +static void +generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from) +{ + fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__); + exit(1); +} + +static void +generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v, + Variable* data, Variable** cl) +{ + Expression* k = new StringLiteralExpression(key); + if (v->dimension == 0) { + t->CreateFromRpcData(addTo, k, v, data, cl); + } + if (v->dimension == 1) { + //t->ReadArrayFromRpcData(addTo, v, data, cl); + fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n", + __FILE__, __LINE__); + } +} + +static void +generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data) +{ + if (v->dimension == 0) { + t->WriteToRpcData(addTo, k, v, data, 0); + } + if (v->dimension == 1) { + //t->WriteArrayToParcel(addTo, v, data); + fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n", + __FILE__, __LINE__); + } +} + +// ================================================= +static string +results_class_name(const string& n) +{ + string str = n; + str[0] = toupper(str[0]); + str.insert(0, "On"); + return str; +} + +static string +results_method_name(const string& n) +{ + string str = n; + str[0] = toupper(str[0]); + str.insert(0, "on"); + return str; +} + +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); + + 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; +} + +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(RPC_BROKER_TYPE, "sendRequest", 6, + new FieldVariable(THIS_VALUE, "_context"), + new StringLiteralExpression(method->name.data), + proxyClass->endpoint, + new MethodCall(_data, "serialize"), + resultParameter, + errorListener)); +} + +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); + 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 + dispatchMethod->statements->Add(realCall); +} + +static void +generate_service_base_methods(const method_type* method, ServiceBaseClass* serviceBaseClass) +{ + arg_type* arg; + StatementBlock* block; + serviceBaseClass->AddMethod(method->name.data, &block); + + // 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; + } + + serviceBaseClass->elements.push_back(decl); + + // The call to decl (from above) + MethodCall* realCall = new MethodCall(THIS_VALUE, 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, + serviceBaseClass->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, serviceBaseClass->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; + } + + // the real call + Variable* _result = NULL; + if (0 == strcmp(method->type.type.data, "void")) { + block->Add(realCall); + } else { + _result = new Variable(decl->returnType, "_result", + decl->returnTypeDimension); + block->Add(new VariableDeclaration(_result, realCall)); + + // marshall the return value + generate_write_to_data(decl->returnType, block, + new StringLiteralExpression("_result"), _result, serviceBaseClass->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) { + generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data), + v, serviceBaseClass->resultData); + } + + arg = arg->next; + } +} + +static void +generate_method(const method_type* method, RpcProxyClass* proxyClass, + ServiceBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass, + int index) +{ + // == 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 dispatch method in the service base class ====================== + generate_service_base_methods(method, serviceBaseClass); +} + +Class* +generate_rpc_interface_class(const interface_type* iface) +{ + // the proxy class + InterfaceType* interfaceType = static_cast<InterfaceType*>( + NAMES.Find(iface->package, iface->name.data)); + RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType); + + // the service base class + ServiceBaseClass* base = new ServiceBaseClass(iface); + proxy->elements.push_back(base); + + // the result dispatcher + ResultDispatcherClass* results = new ResultDispatcherClass(); + + // all the declared methods of the proxy + int index = 0; + interface_item_type* item = iface->interface_items; + while (item != NULL) { + if (item->item_type == METHOD_TYPE) { + generate_method((method_type*)item, proxy, base, results, index); + } + item = item->next; + index++; + } + base->DoneWithMethods(); + + // only add this if there are methods with results / out parameters + if (results->needed) { + proxy->elements.push_back(results); + } + + return proxy; +} + |