Checkpoint adding @home RPC support to aidl

Change-Id: I85534bd58aabdc58a05b76e49f5580196fefcec9
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 @@
     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, 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, 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 @@
         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 @@
     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 @@
     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 @@
     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 @@
 	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* 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_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 @@
     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 @@
     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 @@
 }
 
 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 @@
     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 @@
     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 @@
                                     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 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* 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 92f5b64..50a0ba4 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -29,7 +29,7 @@
 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 @@
             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 @@
             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 @@
         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 @@
                                         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 @@
     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 @@
     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) {
@@ -616,7 +634,7 @@
     string result;
 
     // 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;
 
         // create the path to the destination folder based on the
@@ -723,7 +741,7 @@
             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;
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 @@
 
 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 @@
     /* 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 @@
 %token ARRAY
 %token PARCELABLE
 %token INTERFACE
+%token RPC
 %token IN
 %token OUT
 %token INOUT
@@ -102,6 +103,8 @@
 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 @@
                                                    }
     |   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 @@
                                                         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 @@
 }
 
 // =================================================
-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 @@
     return s;
 }
 
-static string
+string
 append(const char* a, const char* b)
 {
     string s = a;
@@ -257,379 +56,25 @@
     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)
-{
-    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);
-}
-
-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)
 {
+    Class* cl;
+
+    if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
+        cl = generate_binder_interface_class(iface);
+    }
+    else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
+        cl = generate_rpc_interface_class(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 @@
 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;
+}
+