Support custom flattenable types for RPC.

Change-Id: I5c29043baba792ce99d2e9d48bc96d4837b2a808
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index bb090e0..ead5e7a 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -114,7 +114,7 @@
     virtual void Write(FILE* to) = 0;
 };
 
-struct StatementBlock
+struct StatementBlock : public Statement
 {
     vector<Statement*> statements;
 
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 9a58af0..3590255 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -82,8 +82,7 @@
     STRING_TYPE = new StringType();
     NAMES.Add(STRING_TYPE);
 
-    OBJECT_TYPE = new Type("java.lang", "Object",
-            Type::BUILT_IN, false, false);
+    OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
     NAMES.Add(OBJECT_TYPE);
 
     CHAR_SEQUENCE_TYPE = new CharSequenceType();
@@ -95,7 +94,7 @@
     LIST_TYPE = new ListType();
     NAMES.Add(LIST_TYPE);
 
-    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false);
+    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false, false);
     NAMES.Add(TEXT_UTILS_TYPE);
 
     REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
@@ -122,19 +121,18 @@
     PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
     NAMES.Add(PARCELABLE_INTERFACE_TYPE);
 
-    CONTEXT_TYPE = new Type("android.content", "Context",
-                                    Type::BUILT_IN, false, false);
+    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
     NAMES.Add(CONTEXT_TYPE);
 
     RPC_SERVICE_BASE_TYPE = new Type("com.android.athome.service", "AndroidAtHomeService",
-                                    Type::BUILT_IN, false, false);
+                                    Type::BUILT_IN, false, false, false);
     NAMES.Add(RPC_SERVICE_BASE_TYPE);
 
     RPC_DATA_TYPE = new RpcDataType();
     NAMES.Add(RPC_DATA_TYPE);
 
     RPC_BROKER_TYPE = new Type("com.android.athome.utils", "AndroidAtHomeBroker",
-                                    Type::BUILT_IN, false, false);
+                                    Type::BUILT_IN, false, false, false);
     NAMES.Add(RPC_BROKER_TYPE);
 
     RPC_ENDPOINT_INFO_TYPE = new ParcelableType("com.android.athome.rpc", "EndpointInfo",
@@ -150,7 +148,7 @@
     NAMES.Add(RPC_ERROR_TYPE);
 
     RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
-                                    Type::BUILT_IN, false, false);
+                                    Type::BUILT_IN, false, false, false);
     NAMES.Add(RPC_ERROR_LISTENER_TYPE);
 
     CLASSLOADER_TYPE = new ClassLoaderType();
@@ -179,27 +177,30 @@
 
 // ================================================================
 
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canWriteToRpcData,
+        bool canBeOut)
     :m_package(),
      m_name(name),
      m_declFile(""),
      m_declLine(-1),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
+     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     m_qualifiedName = name;
 }
 
 Type::Type(const string& package, const string& name,
-            int kind, bool canWriteToParcel, bool canBeOut,
-            const string& declFile, int declLine)
+            int kind, bool canWriteToParcel, bool canWriteToRpcData,
+            bool canBeOut, const string& declFile, int declLine)
     :m_package(package),
      m_name(name),
      m_declFile(declFile),
      m_declLine(declLine),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
+     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     if (package.length() > 0) {
@@ -339,7 +340,7 @@
           const string& createArrayParcel, const string& readArrayParcel,
           const string& marshallRpc, const string& unmarshallRpc,
           const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
-    :Type(name, BUILT_IN, true, false),
+    :Type(name, BUILT_IN, true, true, false),
      m_marshallParcel(marshallParcel),
      m_unmarshallParcel(unmarshallParcel),
      m_writeArrayParcel(writeArrayParcel),
@@ -407,7 +408,7 @@
 // ================================================================
 
 BooleanType::BooleanType()
-    :Type("boolean", BUILT_IN, true, false)
+    :Type("boolean", BUILT_IN, true, true, false)
 {
 }
 
@@ -468,7 +469,7 @@
 // ================================================================
 
 CharType::CharType()
-    :Type("char", BUILT_IN, true, false)
+    :Type("char", BUILT_IN, true, true, false)
 {
 }
 
@@ -527,7 +528,7 @@
 // ================================================================
 
 StringType::StringType()
-    :Type("java.lang", "String", BUILT_IN, true, false)
+    :Type("java.lang", "String", BUILT_IN, true, true, false)
 {
 }
 
@@ -591,7 +592,7 @@
 // ================================================================
 
 CharSequenceType::CharSequenceType()
-    :Type("java.lang", "CharSequence", BUILT_IN, true, false)
+    :Type("java.lang", "CharSequence", BUILT_IN, true, true, false)
 {
 }
 
@@ -651,7 +652,7 @@
 // ================================================================
 
 RemoteExceptionType::RemoteExceptionType()
-    :Type("android.os", "RemoteException", BUILT_IN, false, false)
+    :Type("android.os", "RemoteException", BUILT_IN, false, false, false)
 {
 }
 
@@ -670,7 +671,7 @@
 // ================================================================
 
 RuntimeExceptionType::RuntimeExceptionType()
-    :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
+    :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false)
 {
 }
 
@@ -690,7 +691,7 @@
 // ================================================================
 
 IBinderType::IBinderType()
-    :Type("android.os", "IBinder", BUILT_IN, true, false)
+    :Type("android.os", "IBinder", BUILT_IN, true, false, false)
 {
 }
 
@@ -729,7 +730,7 @@
 // ================================================================
 
 IInterfaceType::IInterfaceType()
-    :Type("android.os", "IInterface", BUILT_IN, false, false)
+    :Type("android.os", "IInterface", BUILT_IN, false, false, false)
 {
 }
 
@@ -749,7 +750,7 @@
 // ================================================================
 
 BinderType::BinderType()
-    :Type("android.os", "Binder", BUILT_IN, false, false)
+    :Type("android.os", "Binder", BUILT_IN, false, false, false)
 {
 }
 
@@ -770,7 +771,7 @@
 // ================================================================
 
 BinderProxyType::BinderProxyType()
-    :Type("android.os", "BinderProxy", BUILT_IN, false, false)
+    :Type("android.os", "BinderProxy", BUILT_IN, false, false, false)
 {
 }
 
@@ -791,7 +792,7 @@
 // ================================================================
 
 ParcelType::ParcelType()
-    :Type("android.os", "Parcel", BUILT_IN, false, false)
+    :Type("android.os", "Parcel", BUILT_IN, false, false, false)
 {
 }
 
@@ -810,7 +811,7 @@
 // ================================================================
 
 ParcelableInterfaceType::ParcelableInterfaceType()
-    :Type("android.os", "Parcelable", BUILT_IN, false, false)
+    :Type("android.os", "Parcelable", BUILT_IN, false, false, false)
 {
 }
 
@@ -829,7 +830,7 @@
 // ================================================================
 
 MapType::MapType()
-    :Type("java.util", "Map", BUILT_IN, true, true)
+    :Type("java.util", "Map", BUILT_IN, true, false, true)
 {
 }
 
@@ -869,7 +870,7 @@
 // ================================================================
 
 ListType::ListType()
-    :Type("java.util", "List", BUILT_IN, true, true)
+    :Type("java.util", "List", BUILT_IN, true, true, true)
 {
 }
 
@@ -918,7 +919,7 @@
 
 ParcelableType::ParcelableType(const string& package, const string& name,
                         bool builtIn, const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true,
+    :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, false, true,
             declFile, declLine)
 {
 }
@@ -1019,13 +1020,81 @@
                     v, new LiteralExpression(creator)));
 }
 
+// ================================================================
+
+FlattenableType::FlattenableType(const string& package, const string& name,
+                        bool builtIn, const string& declFile, int declLine)
+    :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, false, true, true,
+            declFile, declLine)
+{
+}
+
+string
+FlattenableType::CreatorName() const
+{
+    return QualifiedName() + ".CREATOR";
+}
+
+void
+FlattenableType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags)
+{
+    // if (v != null) {
+    //     RpcData _obj = new RpcData();
+    //     v.writeToRpcData(_obj);
+    //     data.putRpcData(k, obj);
+    // }
+    IfStatement* ifpart = new IfStatement;
+    ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
+    Variable* _obj = new Variable(RPC_DATA_TYPE, "_obj");
+    ifpart->statements->Add(new VariableDeclaration(_obj, new NewExpression(RPC_DATA_TYPE)));
+    ifpart->statements->Add(new MethodCall(v, "writeToRpcData", 1, _obj));
+    ifpart->statements->Add(new MethodCall(data, "putRpcData", 2, k, _obj));
+
+    addTo->Add(ifpart);
+}
+
+void
+FlattenableType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl)
+{
+    // RpcData _obj_XX = data.getRpcData(k);
+    // if (_data_XX != null)
+    //     v = CLASS.RPC_CREATOR.createFromParcel(parcel)
+    // } else {
+    //     v = null;
+    // }
+
+    StatementBlock* block = new StatementBlock;
+    addTo->Add(block);
+
+    Variable* _obj = new Variable(RPC_DATA_TYPE, "_obj");
+    block->Add(new VariableDeclaration(_obj, new MethodCall(data, "getRpcData", 1, k)));
+
+    IfStatement* ifpart = new IfStatement();
+    ifpart->expression = new Comparison(_obj, "!=", NULL_VALUE);
+    ifpart->statements->Add(new Assignment(v,
+                new MethodCall(v->type, "RPC_CREATOR.createFromRpcData", 1, data)));
+
+    IfStatement* elsepart = new IfStatement();
+    ifpart->elseif = elsepart;
+    elsepart->statements->Add(new Assignment(v, NULL_VALUE));
+
+    block->Add(ifpart);
+}
+
+bool
+FlattenableType::CanBeArray() const
+{
+    return true;
+}
 
 // ================================================================
 
 InterfaceType::InterfaceType(const string& package, const string& name,
                         bool builtIn, bool oneway,
                         const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
+    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, false,
                         declFile, declLine)
     ,m_oneway(oneway)
 {
@@ -1064,7 +1133,7 @@
 
 GenericType::GenericType(const string& package, const string& name,
                          const vector<Type*>& args)
-    :Type(package, name, BUILT_IN, true, true)
+    :Type(package, name, BUILT_IN, true, true, true)
 {
     m_args = args;
 
@@ -1210,7 +1279,7 @@
 // ================================================================
 
 RpcDataType::RpcDataType()
-    :Type("com.android.athome.rpc", "RpcData", Type::BUILT_IN, false, false)
+    :Type("com.android.athome.rpc", "RpcData", Type::BUILT_IN, false, true, true)
 {
 }
 
@@ -1232,7 +1301,7 @@
 // ================================================================
 
 ClassLoaderType::ClassLoaderType()
-    :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
+    :Type("java.lang", "ClassLoader", BUILT_IN, false, false, false)
 {
 }
 
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index 97b3a12..fa57840 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -24,9 +24,9 @@
     };
 
                     Type(const string& name, int kind, bool canWriteToParcel,
-                            bool canBeOut);
+                            bool canWriteToRpcData, bool canBeOut);
                     Type(const string& package, const string& name,
-                            int kind, bool canWriteToParcel, bool canBeOut,
+                            int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
                             const string& declFile = "", int declLine = -1);
     virtual         ~Type();
 
@@ -36,7 +36,8 @@
     inline int      Kind() const                { return m_kind; }
     inline string   DeclFile() const            { return m_declFile; }
     inline int      DeclLine() const            { return m_declLine; }
-    inline bool     CanBeMarshalled() const     { return m_canWriteToParcel; }
+    inline bool     CanWriteToParcel() const    { return m_canWriteToParcel; }
+    inline bool     CanWriteToRpcData() const   { return m_canWriteToRpcData; }
     inline bool     CanBeOutParameter() const   { return m_canBeOut; }
     
     virtual string  ImportType() const;
@@ -79,6 +80,7 @@
     int m_declLine;
     int m_kind;
     bool m_canWriteToParcel;
+    bool m_canWriteToRpcData;
     bool m_canBeOut;
 };
 
@@ -373,6 +375,22 @@
                                     Variable* parcel, Variable** cl);
 };
 
+class FlattenableType : public Type
+{
+public:
+                    FlattenableType(const string& package, const string& name,
+                            bool builtIn, const string& declFile, int declLine);
+
+    virtual string  CreatorName() const;
+
+    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 bool    CanBeArray() const;
+};
+
 class InterfaceType : public Type
 {
 public:
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 78404cb..c39e603 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -54,6 +54,10 @@
             parcelable_type* b = (parcelable_type*)d;
             printf("parcelable %s %s;\n", b->package, b->name.data);
         }
+        else if (d->item_type == FLATTENABLE_TYPE) {
+            parcelable_type* b = (parcelable_type*)d;
+            printf("flattenable %s %s;\n", b->package, b->name.data);
+        }
         else {
             printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
         }
@@ -238,7 +242,8 @@
 {
     int err = 0;
     while (items) {
-        if (items->item_type == PARCELABLE_TYPE) {
+        if (items->item_type == PARCELABLE_TYPE
+                || items->item_type == FLATTENABLE_TYPE) {
             parcelable_type* p = (parcelable_type*)items;
             err |= check_filename(filename, p->package, &p->name);
         }
@@ -296,6 +301,11 @@
             type = new ParcelableType(p->package ? p->package : "",
                             p->name.data, false, filename, p->name.lineno);
         }
+        else if (items->item_type == FLATTENABLE_TYPE) {
+            parcelable_type* p = (parcelable_type*)items;
+            type = new FlattenableType(p->package ? p->package : "",
+                            p->name.data, false, filename, p->name.lineno);
+        }
         else if (items->item_type == INTERFACE_TYPE_BINDER
                 || items->item_type == INTERFACE_TYPE_RPC) {
             interface_type* c = (interface_type*)items;
@@ -321,14 +331,14 @@
                 string name = c->name.data;
                 name += ".Stub";
                 Type* stub = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false,
+                                        name, Type::GENERATED, false, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(stub);
 
                 name = c->name.data;
                 name += ".Stub.Proxy";
                 Type* proxy = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false,
+                                        name, Type::GENERATED, false, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(proxy);
             }
@@ -341,7 +351,7 @@
                 string name = c->name.data;
                 name += ".ServiceBase";
                 Type* base = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false,
+                                        name, Type::GENERATED, false, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(base);
             }
@@ -396,7 +406,7 @@
 }
 
 static int
-check_method(const char* filename, method_type* m)
+check_method(const char* filename, int kind, method_type* m)
 {
     int err = 0;
 
@@ -409,7 +419,8 @@
         return err;
     }
 
-    if (!returnType->CanBeMarshalled()) {
+    if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
+                : returnType->CanWriteToRpcData())) {
         fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
                     m->type.type.lineno, m->type.type.data);
         err = 1;
@@ -445,7 +456,7 @@
             goto next;
         }
         
-        if (!t->CanBeMarshalled()) {
+        if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
                         filename, m->type.type.lineno, index,
                         arg->type.type.data, arg->name.data);
@@ -512,8 +523,9 @@
 {
     int err = 0;
     while (items) {
-        // (nothing to check for PARCELABLE_TYPE)
-        if (items->item_type == INTERFACE_TYPE_BINDER) {
+        // (nothing to check for PARCELABLE_TYPE or FLATTENABLE_TYPE)
+        if (items->item_type == INTERFACE_TYPE_BINDER
+                || items->item_type == INTERFACE_TYPE_RPC) {
             map<string,method_type*> methodNames;
             interface_type* c = (interface_type*)items;
 
@@ -522,7 +534,7 @@
                 if (member->item_type == METHOD_TYPE) {
                     method_type* m = (method_type*)member;
 
-                    err |= check_method(filename, m);
+                    err |= check_method(filename, items->item_type, m);
 
                     // prevent duplicate methods
                     if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -568,19 +580,22 @@
         else if (next->item_type == PARCELABLE_TYPE) {
             lineno = ((parcelable_type*)next)->parcelable_token.lineno;
         }
+        else if (next->item_type == FLATTENABLE_TYPE) {
+            lineno = ((parcelable_type*)next)->parcelable_token.lineno;
+        }
         fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
                             filename, lineno);
         return 1;
     }
 
-    if (items->item_type == PARCELABLE_TYPE) {
+    if (items->item_type == PARCELABLE_TYPE || items->item_type == FLATTENABLE_TYPE) {
         *onlyParcelable = true;
         if (options.failOnParcelable) {
             fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
-                            " parcelables,\n", filename,
+                            " parcelables or flattenables,\n", filename,
                             ((parcelable_type*)items)->parcelable_token.lineno);
-            fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
-                            "don't need to go in the Makefile.\n", filename,
+            fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+                            "may not go in the Makefile.\n", filename,
                             ((parcelable_type*)items)->parcelable_token.lineno);
             return 1;
         }
@@ -680,7 +695,7 @@
         interface_type* type = (interface_type*)items;
 
         return generate_outputFileName2(options, type->name, type->package);
-    } else if (items->item_type == PARCELABLE_TYPE) {
+    } else if (items->item_type == PARCELABLE_TYPE || items->item_type == FLATTENABLE_TYPE) {
         parcelable_type* type = (parcelable_type*)items;
         return generate_outputFileName2(options, type->name, type->package);
     }
@@ -765,6 +780,20 @@
             parcl->semicolon_token.data = strdup(";");
             doc = (document_item_type*)parcl;
         }
+        else if (0 == strcmp("flattenable", type)) {
+            parcelable_type* parcl = (parcelable_type*)malloc(
+                    sizeof(parcelable_type));
+            memset(parcl, 0, sizeof(parcelable_type));
+            parcl->document_item.item_type = FLATTENABLE_TYPE;
+            parcl->parcelable_token.lineno = lineno;
+            parcl->parcelable_token.data = strdup(type);
+            parcl->package = packagename ? strdup(packagename) : NULL;
+            parcl->name.lineno = lineno;
+            parcl->name.data = strdup(classname);
+            parcl->semicolon_token.lineno = lineno;
+            parcl->semicolon_token.data = strdup(";");
+            doc = (document_item_type*)parcl;
+        }
         else if (0 == strcmp("interface", type)) {
             interface_type* iface = (interface_type*)malloc(
                     sizeof(interface_type));
@@ -949,6 +978,15 @@
                 line += '.';
             }
             line += parcelable->name.data;
+        }
+        else if (doc->item_type == FLATTENABLE_TYPE) {
+            line = "parcelable ";
+            parcelable_type* parcelable = (parcelable_type*)doc;
+            if (parcelable->package) {
+                line += parcelable->package;
+                line += '.';
+            }
+            line += parcelable->name.data;
         } else {
             line = "interface ";
             interface_type* iface = (interface_type*)doc;
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index 985f646..b490a59 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -64,6 +64,7 @@
 
 enum {
     PARCELABLE_TYPE = 12,
+    FLATTENABLE_TYPE,
     INTERFACE_TYPE_BINDER,
     INTERFACE_TYPE_RPC
 };
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 8092366..7c5290c 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; }
+flattenable     { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
 rpc             { SET_BUFFER(INTERFACE); return RPC; }
 in              { SET_BUFFER(IN); return IN; }
 out             { SET_BUFFER(OUT); return OUT; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index 965d936..12bb3d7 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 FLATTENABLE
 %token RPC
 %token IN
 %token OUT
@@ -78,7 +79,7 @@
     ;
 
 parcelable_decl:
-        PARCELABLE IDENTIFIER ';'                  { 
+        PARCELABLE IDENTIFIER ';'                   {
                                                         parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type));
                                                         b->document_item.item_type = PARCELABLE_TYPE;
                                                         b->document_item.next = NULL;
@@ -98,6 +99,27 @@
                                                                      g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.parcelable = NULL;
                                                     }
+    |   FLATTENABLE IDENTIFIER ';'                  {
+                                                        parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type));
+                                                        b->document_item.item_type = FLATTENABLE_TYPE;
+                                                        b->document_item.next = NULL;
+                                                        b->parcelable_token = $1.buffer;
+                                                        b->name = $2.buffer;
+                                                        b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+                                                        b->semicolon_token = $3.buffer;
+                                                        $$.parcelable = b;
+                                                    }
+    |   FLATTENABLE ';'                             {
+                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
+                                                                     g_currentFilename, $1.buffer.lineno);
+                                                        $$.parcelable = NULL;
+                                                    }
+    |   FLATTENABLE error ';'                       {
+                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
+                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+                                                        $$.parcelable = NULL;
+                                                    }
+
     ;
 
 interface_header:
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
index 69e9c3d..53a11f2 100644
--- a/tools/aidl/generate_java_rpc.cpp
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -6,7 +6,7 @@
 #include <string.h>
 
 Type* SERVICE_CONTAINER_TYPE = new Type("com.android.athome.service",
-        "AndroidAtHomeServiceContainer", Type::BUILT_IN, false, false);
+        "AndroidAtHomeServiceContainer", Type::BUILT_IN, false, false, false);
 
 static string
 format_int(int n)
@@ -237,7 +237,7 @@
 {
     this->modifiers = PRIVATE | FINAL;
     this->what = Class::CLASS;
-    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false);
+    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
     this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
 
     // methodId
@@ -373,7 +373,7 @@
 
     string resultsMethodName = results_method_name(method->name.data);
     Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
-            Type::GENERATED, false, false);
+            Type::GENERATED, false, false, false);
 
     if (!method->oneway) {
         Class* resultsClass = new Class;