Make array types their own type object

We now offer much simpler functionality from type objects. In addition,
we attach type objects to the appropriate AST nodes, so generators can
just read and trust the model.

Test: Unit tests pass
Bug: 25939691
Change-Id: Id274a933c7bd4f1e5d6daf2b89a64b3553a37069
diff --git a/aidl.cpp b/aidl.cpp
index 85d9772..6ca7bd5 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -198,6 +198,15 @@
       err = 1;  // return type is invalid
     }
 
+    const ValidatableType* return_type =
+        types->GetValidatableType(m->GetType().GetName());
+
+    if (m->GetType().IsArray()) {
+      return_type = return_type->ArrayType();
+    }
+
+    m->GetMutableType()->SetLanguageType(return_type);
+
     if (oneway && m->GetType().GetName() != "void") {
         cerr << filename << ":" << m->GetLine()
             << " oneway method '" << m->GetName() << "' cannot return a value"
@@ -212,6 +221,15 @@
         err = 1;
       }
 
+      const ValidatableType* arg_type =
+          types->GetValidatableType(arg->GetType().GetName());
+
+      if (arg->GetType().IsArray()) {
+        arg_type = arg_type->ArrayType();
+      }
+
+      arg->GetMutableType()->SetLanguageType(arg_type);
+
       if (oneway && arg->IsOut()) {
         cerr << filename << ":" << m->GetLine()
             << " oneway method '" << m->GetName()
@@ -544,6 +562,8 @@
     err = AidlError::BAD_TYPE;
   }
 
+  interface->SetLanguageType(types->GetValidatableType(interface->GetCanonicalName()));
+
   for (const auto& import : p.GetImports()) {
     // If we skipped an unresolved import above (see comment there) we'll have
     // an empty bucket here.
diff --git a/aidl_language.h b/aidl_language.h
index ae7a179..a1956cb 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -35,6 +35,14 @@
   DISALLOW_COPY_AND_ASSIGN(AidlNode);
 };
 
+namespace android {
+namespace aidl {
+
+class ValidatableType;
+
+}  // namespace aidl
+}  // namespace android
+
 class AidlType : public AidlNode {
  public:
   AidlType(const std::string& name, unsigned line,
@@ -48,11 +56,21 @@
 
   std::string ToString() const;
 
+  void SetLanguageType(const android::aidl::ValidatableType* language_type) {
+    language_type_ = language_type;
+  }
+
+  template<typename T>
+  const T* GetLanguageType() const {
+    return reinterpret_cast<const T*>(language_type_);
+  }
+
  private:
   std::string name_;
   unsigned line_;
   bool is_array_;
   std::string comments_;
+  const android::aidl::ValidatableType* language_type_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(AidlType);
 };
@@ -74,6 +92,7 @@
   std::string GetName() const { return name_; }
   int GetLine() const { return line_; }
   const AidlType& GetType() const { return *type_; }
+  AidlType* GetMutableType() { return type_.get(); }
 
   std::string ToString() const;
 
@@ -132,6 +151,7 @@
 
   const std::string& GetComments() const { return comments_; }
   const AidlType& GetType() const { return *type_; }
+  AidlType* GetMutableType() { return type_.get(); }
   bool IsOneway() const { return oneway_; }
   const std::string& GetName() const { return name_; }
   unsigned GetLine() const { return line_; }
@@ -254,6 +274,13 @@
   std::string GetCanonicalName() const;
   const std::vector<std::string>& GetSplitPackage() const { return package_; }
 
+  void SetLanguageType(const android::aidl::ValidatableType* language_type) {
+    language_type_ = language_type;
+  }
+
+  template<typename T>
+  const T* GetLanguageType() const { return reinterpret_cast<const T*>(language_type_); }
+
  private:
   std::string name_;
   std::string comments_;
@@ -263,6 +290,8 @@
   std::vector<std::unique_ptr<AidlConstant>> constants_;
   std::vector<std::string> package_;
 
+  const android::aidl::ValidatableType* language_type_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(AidlInterface);
 };
 
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 6abe385..6f1b300 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -221,9 +221,9 @@
   EXPECT_NE(nullptr, cpp_parse_result);
   auto cpp_type = cpp_types_.Find("Bar");
   ASSERT_NE(nullptr, cpp_type);
-  EXPECT_EQ("::p::Bar", cpp_type->CppType(false));
+  EXPECT_EQ("::p::Bar", cpp_type->CppType());
   set<string> headers;
-  cpp_type->GetHeaders(false, &headers);
+  cpp_type->GetHeaders(&headers);
   EXPECT_EQ(1u, headers.size());
   EXPECT_EQ(1u, headers.count("baz/header"));
 
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 54d1911..ce4c800 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -112,9 +112,9 @@
     if (for_declaration) {
       // Method declarations need types, pointers to out params, and variable
       // names that match the .aidl specification.
-      const Type* type = types.Find(a->GetType().GetName());
+      const Type* type = a->GetType().GetLanguageType<Type>();
 
-      literal = type->CppType(a->GetType().IsArray());
+      literal = type->CppType();
 
       if (a->IsOut()) {
         literal = literal + "*";
@@ -134,13 +134,13 @@
     method_arguments.push_back(literal);
   }
 
-  const Type* return_type = types.Find(method.GetType().GetName());
+  const Type* return_type = method.GetType().GetLanguageType<Type>();
 
   if (return_type != types.VoidType()) {
     string literal;
     if (for_declaration) {
       literal = StringPrintf(
-          "%s* %s", return_type->CppType(method.GetType().IsArray()).c_str(),
+          "%s* %s", return_type->CppType().c_str(),
           kReturnVarName);
     } else {
       literal = string{"&"} + kReturnVarName;
@@ -196,10 +196,10 @@
 
 bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a,
                           StatementBlock* b) {
-  const Type* cpp_type = types.Find(a.GetType().GetName());
+  const Type* cpp_type = a.GetType().GetLanguageType<Type>();
   if (!cpp_type) { return false; }
 
-  string type = cpp_type->CppType(a.GetType().IsArray());
+  string type = cpp_type->CppType();
 
   b->AddLiteral(type + " " + BuildVarName(a));
   return true;
@@ -301,9 +301,8 @@
   //     _aidl_ret_status = _aidl_data.WriteInt32(in_param_name);
   //     if (_aidl_ret_status != ::android::OK) { goto error; }
   for (const AidlArgument* a : method.GetInArguments()) {
-    const Type* type = types.Find(a->GetType().GetName());
-    string method =
-      type->WriteToParcelMethod(a->GetType().IsArray());
+    const Type* type = a->GetType().GetLanguageType<Type>();
+    string method = type->WriteToParcelMethod();
 
     string var_name = ((a->IsOut()) ? "*" : "") + a->GetName();
     var_name = type->WriteCast(var_name);
@@ -351,10 +350,9 @@
   // status" if we are a oneway method, so no more fear of accessing reply.
 
   // If the method is expected to return something, read it first by convention.
-  const Type* return_type = types.Find(method.GetType().GetName());
+  const Type* return_type = method.GetType().GetLanguageType<Type>();
   if (return_type != types.VoidType()) {
-    string method_call = return_type->ReadFromParcelMethod(
-        method.GetType().IsArray());
+    string method_call = return_type->ReadFromParcelMethod();
     b->AddStatement(new Assignment(
         kAndroidStatusVarName,
         new MethodCall(StringPrintf("%s.%s", kReplyVarName,
@@ -368,8 +366,7 @@
     //     _aidl_ret_status = _aidl_reply.ReadInt32(out_param_name);
     //     if (_aidl_status != ::android::OK) { goto _aidl_error; }
     string method =
-      types.Find(a->GetType().GetName())
-        ->ReadFromParcelMethod(a->GetType().IsArray());
+      a->GetType().GetLanguageType<Type>()->ReadFromParcelMethod();
 
     b->AddStatement(new Assignment(
         kAndroidStatusVarName,
@@ -436,10 +433,10 @@
   }
 
   // Declare a variable to hold the return value.
-  const Type* return_type = types.Find(method.GetType().GetName());
+  const Type* return_type = method.GetType().GetLanguageType<Type>();
   if (return_type != types.VoidType()) {
     b->AddLiteral(StringPrintf(
-        "%s %s", return_type->CppType(method.GetType().IsArray()).c_str(),
+        "%s %s", return_type->CppType().c_str(),
         kReturnVarName));
   }
 
@@ -458,8 +455,8 @@
     // Deserialization looks roughly like:
     //     _aidl_ret_status = _aidl_data.ReadInt32(&in_param_name);
     //     if (_aidl_ret_status != ::android::OK) { break; }
-    const Type* type = types.Find(a->GetType().GetName());
-    string readMethod = type->ReadFromParcelMethod(a->GetType().IsArray());
+    const Type* type = a->GetType().GetLanguageType<Type>();
+    string readMethod = type->ReadFromParcelMethod();
 
     b->AddStatement(new Assignment{
         kAndroidStatusVarName,
@@ -493,7 +490,7 @@
   if (return_type != types.VoidType()) {
     string writeMethod =
         string(kReplyVarName) + "->" +
-        return_type->WriteToParcelMethod(method.GetType().IsArray());
+        return_type->WriteToParcelMethod();
     b->AddStatement(new Assignment{
         kAndroidStatusVarName, new MethodCall{writeMethod,
         ArgList{return_type->WriteCast(kReturnVarName)}}});
@@ -505,8 +502,8 @@
     // Serialization looks roughly like:
     //     _aidl_ret_status = data.WriteInt32(out_param_name);
     //     if (_aidl_ret_status != ::android::OK) { break; }
-    const Type* type = types.Find(a->GetType().GetName());
-    string writeMethod = type->WriteToParcelMethod(a->GetType().IsArray());
+    const Type* type = a->GetType().GetLanguageType<Type>();
+    string writeMethod = type->WriteToParcelMethod();
 
     b->AddStatement(new Assignment{
         kAndroidStatusVarName,
@@ -682,12 +679,12 @@
 
   for (const auto& method : interface.GetMethods()) {
     for (const auto& argument : method->GetArguments()) {
-      const Type* type = types.Find(argument->GetType().GetName());
-      type->GetHeaders(argument->GetType().IsArray(), &includes);
+      const Type* type = argument->GetType().GetLanguageType<Type>();
+      type->GetHeaders(&includes);
     }
 
-    const Type* return_type = types.Find(method->GetType().GetName());
-    return_type->GetHeaders(method->GetType().IsArray(), &includes);
+    const Type* return_type = method->GetType().GetLanguageType<Type>();
+    return_type->GetHeaders(&includes);
   }
 
   unique_ptr<ClassDecl> if_class{
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index 40e0549..f595a2c 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -17,7 +17,7 @@
 class StubClass : public Class
 {
 public:
-    StubClass(const Type* type, const Type* interfaceType,
+    StubClass(const Type* type, const InterfaceType* interfaceType,
               JavaTypeNamespace* types);
     virtual ~StubClass();
 
@@ -27,12 +27,12 @@
     Variable* transact_flags;
     SwitchStatement* transact_switch;
 private:
-    void make_as_interface(const Type* interfaceType, JavaTypeNamespace* types);
+    void make_as_interface(const InterfaceType* interfaceType, JavaTypeNamespace* types);
 
     DISALLOW_COPY_AND_ASSIGN(StubClass);
 };
 
-StubClass::StubClass(const Type* type, const Type* interfaceType,
+StubClass::StubClass(const Type* type, const InterfaceType* interfaceType,
                      JavaTypeNamespace* types)
     :Class()
 {
@@ -103,7 +103,7 @@
 }
 
 void
-StubClass::make_as_interface(const Type *interfaceType,
+StubClass::make_as_interface(const InterfaceType *interfaceType,
                              JavaTypeNamespace* types)
 {
     Variable* obj = new Variable(types->IBinderType(), "obj");
@@ -147,9 +147,7 @@
         instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
     m->statements->Add(instOfStatement);
 
-    string proxyType = interfaceType->QualifiedName();
-    proxyType += ".Stub.Proxy";
-    NewExpression* ne = new NewExpression(types->Find(proxyType));
+    NewExpression* ne = new NewExpression(interfaceType->GetProxy());
     ne->arguments.push_back(obj);
     m->statements->Add(new ReturnStatement(ne));
 
@@ -228,36 +226,21 @@
 generate_write_to_parcel(const 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);
-    }
+    t->WriteToParcel(addTo, v, parcel, flags);
 }
 
 static void
 generate_create_from_parcel(const 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);
-    }
+    t->CreateFromParcel(addTo, v, parcel, cl);
 }
 
 static void
 generate_read_from_parcel(const 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);
-    }
+    t->ReadFromParcel(addTo, v, parcel, cl);
 }
 
 
@@ -297,13 +280,13 @@
     Method* decl = new Method;
         decl->comment = method.GetComments();
         decl->modifiers = PUBLIC;
-        decl->returnType = types->Find(method.GetType().GetName());
+        decl->returnType = method.GetType().GetLanguageType<Type>();
         decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
         decl->name = method.GetName();
 
     for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
         decl->parameters.push_back(new Variable(
-                            types->Find(arg->GetType().GetName()), arg->GetName(),
+                            arg->GetType().GetLanguageType<Type>(), arg->GetName(),
                             arg->GetType().IsArray() ? 1 : 0));
     }
 
@@ -325,7 +308,7 @@
     Variable* cl = NULL;
     VariableFactory stubArgs("_arg");
     for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
-        const Type* t = types->Find(arg->GetType().GetName());
+        const Type* t = arg->GetType().GetLanguageType<Type>();
         Variable* v = stubArgs.Get(t);
         v->dimension = arg->GetType().IsArray() ? 1 : 0;
 
@@ -378,7 +361,7 @@
     // out parameters
     i = 0;
     for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
-        const Type* t = types->Find(arg->GetType().GetName());
+        const Type* t = arg->GetType().GetLanguageType<Type>();
         Variable* v = stubArgs.Get(i++);
 
         if (arg->GetDirection() & AidlArgument::OUT_DIR) {
@@ -397,13 +380,13 @@
     Method* proxy = new Method;
         proxy->comment = method.GetComments();
         proxy->modifiers = PUBLIC | OVERRIDE;
-        proxy->returnType = types->Find(method.GetType().GetName());
+        proxy->returnType = method.GetType().GetLanguageType<Type>();
         proxy->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
         proxy->name = method.GetName();
         proxy->statements = new StatementBlock;
         for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
             proxy->parameters.push_back(new Variable(
-                            types->Find(arg->GetType().GetName()), arg->GetName(),
+                            arg->GetType().GetLanguageType<Type>(), arg->GetName(),
                             arg->GetType().IsArray() ? 1 : 0));
         }
         proxy->exceptions.push_back(types->RemoteExceptionType());
@@ -442,7 +425,7 @@
 
     // the parameters
     for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
-        const Type* t = types->Find(arg->GetType().GetName());
+        const Type* t = arg->GetType().GetLanguageType<Type>();
         Variable* v = new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
         AidlArgument::Direction dir = arg->GetDirection();
         if (dir == AidlArgument::OUT_DIR && arg->GetType().IsArray()) {
@@ -483,7 +466,7 @@
 
         // the out/inout parameters
         for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
-            const Type* t = types->Find(arg->GetType().GetName());
+            const Type* t = arg->GetType().GetLanguageType<Type>();
             Variable* v = new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
             if (arg->GetDirection() & AidlArgument::OUT_DIR) {
                 generate_read_from_parcel(t, tryStatement->statements,
@@ -526,8 +509,7 @@
 generate_binder_interface_class(const AidlInterface* iface,
                                 JavaTypeNamespace* types)
 {
-    const InterfaceType* interfaceType = static_cast<const InterfaceType*>(
-        types->Find(iface->GetCanonicalName()));
+    const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
 
     // the interface class
     Class* interface = new Class;
@@ -539,14 +521,14 @@
 
     // the stub inner class
     StubClass* stub = new StubClass(
-        types->Find(iface->GetCanonicalName() + ".Stub"),
+        interfaceType->GetStub(),
         interfaceType, types);
     interface->elements.push_back(stub);
 
     // the proxy inner class
     ProxyClass* proxy = new ProxyClass(
         types,
-        types->Find(iface->GetCanonicalName() + ".Stub.Proxy"),
+        interfaceType->GetProxy(),
         interfaceType);
     stub->elements.push_back(proxy);
 
diff --git a/type_cpp.cpp b/type_cpp.cpp
index 39d44a2..77a3382 100644
--- a/type_cpp.cpp
+++ b/type_cpp.cpp
@@ -44,6 +44,7 @@
 const char kNoPackage[] = "";
 const char kNoHeader[] = "";
 const char kNoValidMethod[] = "";
+Type* const kNoArrayType = nullptr;
 
 bool is_cpp_keyword(const std::string& str) {
   static const std::vector<std::string> kCppKeywords{
@@ -68,21 +69,60 @@
 class VoidType : public Type {
  public:
   VoidType() : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "void",
-                    kNoHeader, "void", kNoValidMethod, kNoValidMethod) {}
+                    {}, "void", kNoValidMethod, kNoValidMethod) {}
   virtual ~VoidType() = default;
   bool CanBeOutParameter() const override { return false; }
   bool CanWriteToParcel() const override { return false; }
 };  // class VoidType
 
+class PrimitiveType : public Type {
+ public:
+  PrimitiveType(int kind,  // from ValidatableType
+                const std::string& package,
+                const std::string& aidl_type,
+                const std::string& header,
+                const std::string& cpp_type,
+                const std::string& read_method,
+                const std::string& write_method,
+                const std::string& read_array_method,
+                const std::string& write_array_method)
+      : Type(kind, package, aidl_type, {header}, cpp_type, read_method,
+             write_method, new PrimitiveType(kind, package, aidl_type + "[]",
+                                             header,
+                                             "::std::vector<" + cpp_type + ">",
+                                             read_array_method,
+                                             write_array_method)) {}
+  virtual ~PrimitiveType() = default;
+  bool IsCppPrimitive() const override { return true; }
+  bool CanBeOutParameter() const override { return is_array_; }
+
+ protected:
+  PrimitiveType(int kind,  // from ValidatableType
+                const std::string& package,
+                const std::string& aidl_type,
+                const std::string& header,
+                const std::string& cpp_type,
+                const std::string& read_method,
+                const std::string& write_method)
+      : Type(kind, package, aidl_type, {header, "vector"}, cpp_type, read_method,
+             write_method) {
+    is_array_ = true;
+  }
+
+ private:
+  bool is_array_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(PrimitiveType);
+};  // class PrimitiveType
+
 class BinderType : public Type {
  public:
   BinderType(const AidlInterface& interface, const std::string& src_file_name)
       : Type(ValidatableType::KIND_GENERATED,
              interface.GetPackage(), interface.GetName(),
-             GetCppHeader(interface), GetCppName(interface),
+             {GetCppHeader(interface)}, GetCppName(interface),
              "readStrongBinder", "writeStrongBinder",
-             kNoValidMethod, kNoValidMethod,
-             src_file_name, interface.GetLine()) {}
+             kNoArrayType, src_file_name, interface.GetLine()) {}
   virtual ~BinderType() = default;
 
   string WriteCast(const string& val) const override {
@@ -110,15 +150,34 @@
   }
 };
 
+class ParcelableArrayType : public Type {
+ public:
+  ParcelableArrayType(const AidlParcelable& parcelable,
+                      const std::string& src_file_name)
+      : Type(ValidatableType::KIND_PARCELABLE,
+             parcelable.GetPackage(), parcelable.GetName(),
+             {parcelable.GetCppHeader(), "vector"}, GetCppName(parcelable),
+             "readParcelableVector", "writeParcelableVector",
+             kNoArrayType, src_file_name, parcelable.GetLine()) {}
+  virtual ~ParcelableArrayType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  static string GetCppName(const AidlParcelable& parcelable) {
+    return "::std::vector<" + Join(parcelable.GetSplitPackage(), "::") +
+        "::" + parcelable.GetName() + ">";
+  }
+};
+
 class ParcelableType : public Type {
  public:
   ParcelableType(const AidlParcelable& parcelable,
                  const std::string& src_file_name)
       : Type(ValidatableType::KIND_PARCELABLE,
              parcelable.GetPackage(), parcelable.GetName(),
-             parcelable.GetCppHeader(), GetCppName(parcelable),
+             {parcelable.GetCppHeader()}, GetCppName(parcelable),
              "readParcelable", "writeParcelable",
-             "readParcelableVector", "writeParcelableVector",
+             new ParcelableArrayType(parcelable, src_file_name),
              src_file_name, parcelable.GetLine()) {}
   virtual ~ParcelableType() = default;
   bool CanBeOutParameter() const override { return true; }
@@ -134,20 +193,12 @@
  public:
   StringListType()
       : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List<String>",
-            "utils/String16.h", "::std::vector<::android::String16>",
+             {"utils/String16.h", "vector"},
+             "::std::vector<::android::String16>",
              "readString16Vector", "writeString16Vector") {}
   virtual ~StringListType() = default;
   bool CanBeOutParameter() const override { return true; }
 
-  void GetHeaders(bool is_array, set<string>* headers) const override {
-    if (is_array) {
-      LOG(FATAL) << "Type checking did not catch that List<String> "
-                    "was marked as array";
-    }
-    Type::GetHeaders(is_array, headers);
-    headers->insert("vector");
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(StringListType);
 };  // class StringListType
@@ -156,21 +207,12 @@
  public:
   BinderListType()
       : Type(ValidatableType::KIND_BUILT_IN, "java.util",
-             "List<android.os.IBinder>", "binder/IBinder.h",
+             "List<android.os.IBinder>", {"binder/IBinder.h", "vector"},
              "::std::vector<::android::sp<::android::IBinder>>",
              "readStrongBinderVector", "writeStrongBinderVector") {}
   virtual ~BinderListType() = default;
   bool CanBeOutParameter() const override { return true; }
 
-  void GetHeaders(bool is_array, set<string>* headers) const override {
-    if (is_array) {
-      LOG(FATAL) << "Type checking did not catch that List<Binder> "
-                    "was marked as array";
-    }
-    Type::GetHeaders(is_array, headers);
-    headers->insert("vector");
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(BinderListType);
 };  // class BinderListType
@@ -180,57 +222,22 @@
 Type::Type(int kind,
            const std::string& package,
            const std::string& aidl_type,
-           const string& header,
+           const vector<string>& headers,
            const string& cpp_type,
            const string& read_method,
            const string& write_method,
-           const string& read_array_method,
-           const string& write_array_method,
+           Type* array_type,
            const string& src_file_name,
            int line)
     : ValidatableType(kind, package, aidl_type, src_file_name, line),
-      header_(header),
+      headers_(headers),
       aidl_type_(aidl_type),
       cpp_type_(cpp_type),
       parcel_read_method_(read_method),
       parcel_write_method_(write_method),
-      parcel_read_array_method_(read_array_method),
-      parcel_write_array_method_(write_array_method) {}
+      array_type_(array_type) {}
 
-bool Type::CanBeArray() const { return ! parcel_read_array_method_.empty(); }
 bool Type::CanWriteToParcel() const { return true; }
-void Type::GetHeaders(bool is_array, set<string>* headers) const {
-  if (!header_.empty()) {
-    headers->insert(header_);
-  }
-  if (is_array) {
-    headers->insert("vector");
-  }
-}
-
-string Type::CppType(bool is_array) const {
-  if (is_array) {
-    return "::std::vector<" + cpp_type_ + ">";
-  } else {
-    return cpp_type_;
-  }
-}
-
-const string& Type::ReadFromParcelMethod(bool is_array) const {
-  if (is_array) {
-    return parcel_read_array_method_;
-  } else {
-    return parcel_read_method_;
-  }
-}
-
-const string& Type::WriteToParcelMethod(bool is_array) const {
-  if (is_array) {
-    return parcel_write_array_method_;
-  } else {
-    return parcel_write_method_;
-  }
-}
 
 void TypeNamespace::Init() {
   Add(new PrimitiveType(
@@ -263,14 +270,20 @@
       kNoHeader, "char16_t", "readChar", "writeChar",
       "readCharVector", "writeCharVector"));
 
+  Type* string_array_type = new Type(ValidatableType::KIND_BUILT_IN,
+                                     kNoPackage, "String[]",
+                                     {"utils/String16.h", "vector"},
+                                     "::std::vector<::android::String16>",
+                                     "readString16Vector",
+                                     "writeString16Vector");
   string_type_ = new Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "String",
-                          "utils/String16.h", "::android::String16",
+                          {"utils/String16.h"}, "::android::String16",
                           "readString16", "writeString16",
-                          "readString16Vector", "writeString16Vector");
+                          string_array_type);
   Add(string_type_);
 
   ibinder_type_ = new Type(ValidatableType::KIND_BUILT_IN, "android.os",
-                           "IBinder", "binder/IBinder.h",
+                           "IBinder", {"binder/IBinder.h"},
                            "::android::sp<::android::IBinder>", "readStrongBinder",
                            "writeStrongBinder");
   Add(ibinder_type_);
@@ -278,11 +291,16 @@
   Add(new BinderListType());
   Add(new StringListType());
 
+  Type* fd_vector_type = new Type(
+      ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor[]",
+      {"nativehelper/ScopedFd.h", "vector"}, "::std::vector<::ScopedFd>",
+      "readUniqueFileDescriptorVector", "writeUniqueFileDescriptorVector");
+
   Add(new Type(
       ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor",
-      "nativehelper/ScopedFd.h", "::ScopedFd",
+      {"nativehelper/ScopedFd.h"}, "::ScopedFd",
       "readUniqueFileDescriptor", "writeUniqueFileDescriptor",
-      "readUniqueFileDescriptorVector", "writeUniqueFileDescriptorVector"));
+      fd_vector_type));
 
   void_type_ = new class VoidType();
   Add(void_type_);
diff --git a/type_cpp.h b/type_cpp.h
index 0412ec7..fb474ab 100644
--- a/type_cpp.h
+++ b/type_cpp.h
@@ -35,55 +35,55 @@
   Type(int kind,  // from ValidatableType
        const std::string& package,
        const std::string& aidl_type,
-       const std::string& header,
+       const std::vector<std::string>& header,
        const std::string& cpp_type,
        const std::string& read_method,
        const std::string& write_method,
-       const std::string& read_array_method = "",
-       const std::string& write_array_method = "",
+       Type* array_type = nullptr,
        const std::string& src_file_name = "",
        int line = -1);
   virtual ~Type() = default;
 
   // overrides of ValidatableType
-  bool CanBeArray() const override;
   bool CanBeOutParameter() const override { return false; }
   bool CanWriteToParcel() const override;
 
-  std::string CppType(bool is_array) const;
-  virtual void GetHeaders(bool is_array, std::set<std::string>* headers) const;
-  const std::string& ReadFromParcelMethod(bool is_array) const;
-  const std::string& WriteToParcelMethod(bool is_array) const;
+  const Type* ArrayType() const override { return array_type_.get(); }
+  std::string CppType() const { return cpp_type_; }
+  const std::string& ReadFromParcelMethod() const {
+    return parcel_read_method_;
+  }
+  const std::string& WriteToParcelMethod() const {
+    return parcel_write_method_;
+  }
+
+  void GetHeaders(std::set<std::string>* headers) const {
+    for (std::string header : headers_) {
+      if (!header.empty()) {
+        headers->insert(header);
+      }
+    }
+  }
   virtual bool IsCppPrimitive() const { return false; }
   virtual std::string WriteCast(const std::string& value) const {
     return value;
   }
 
  private:
-  // |header| is the header we must include to use this type
-  const std::string header_;
+  // |headers| are the headers we must include to use this type
+  const std::vector<std::string> headers_;
   // |aidl_type| is what we find in the yacc generated AST (e.g. "int").
   const std::string aidl_type_;
   // |cpp_type| is what we use in the generated C++ code (e.g. "int32_t").
   const std::string cpp_type_;
   const std::string parcel_read_method_;
   const std::string parcel_write_method_;
-  const std::string parcel_read_array_method_;
-  const std::string parcel_write_array_method_;
+
+  const std::unique_ptr<Type> array_type_;
 
   DISALLOW_COPY_AND_ASSIGN(Type);
 };  // class Type
 
-class PrimitiveType : public Type {
- public:
-  using Type::Type;
-  virtual ~PrimitiveType() = default;
-  bool IsCppPrimitive() const override { return true; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PrimitiveType);
-};  // class PrimitiveType
-
 class TypeNamespace : public ::android::aidl::LanguageTypeNamespace<Type> {
  public:
   TypeNamespace() = default;
diff --git a/type_cpp_unittest.cpp b/type_cpp_unittest.cpp
index 8e8a557..7138d13 100644
--- a/type_cpp_unittest.cpp
+++ b/type_cpp_unittest.cpp
@@ -33,18 +33,18 @@
 };
 
 TEST_F(CppTypeNamespaceTest, HasSomeBasicTypes) {
-  EXPECT_NE(types_.Find("byte"), nullptr);
-  EXPECT_NE(types_.Find("int"), nullptr);
-  EXPECT_NE(types_.Find("long"), nullptr);
-  EXPECT_NE(types_.Find("float"), nullptr);
-  EXPECT_NE(types_.Find("double"), nullptr);
-  EXPECT_NE(types_.Find("boolean"), nullptr);
-  EXPECT_NE(types_.Find("char"), nullptr);
-  EXPECT_NE(types_.Find("String"), nullptr);
+  EXPECT_TRUE(types_.HasType("byte"));
+  EXPECT_TRUE(types_.HasType("int"));
+  EXPECT_TRUE(types_.HasType("long"));
+  EXPECT_TRUE(types_.HasType("float"));
+  EXPECT_TRUE(types_.HasType("double"));
+  EXPECT_TRUE(types_.HasType("boolean"));
+  EXPECT_TRUE(types_.HasType("char"));
+  EXPECT_TRUE(types_.HasType("String"));
 }
 
 TEST_F(CppTypeNamespaceTest, SupportsListString) {
-  EXPECT_NE(types_.Find("List<String>"), nullptr);
+  EXPECT_TRUE(types_.HasType("List<String>"));
 }
 
 }  // namespace cpp
diff --git a/type_java.cpp b/type_java.cpp
index d89ac4b..5c0bc99 100644
--- a/type_java.cpp
+++ b/type_java.cpp
@@ -82,30 +82,6 @@
                                    m_qualifiedName + " */"));
 }
 
-void Type::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                              Variable* parcel, int flags) const {
-  fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", __FILE__,
-          __LINE__, m_qualifiedName.c_str());
-  addTo->Add(new LiteralExpression("/* WriteArrayToParcel error " +
-                                   m_qualifiedName + " */"));
-}
-
-void Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                 Variable* parcel, Variable**) const {
-  fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", __FILE__,
-          __LINE__, m_qualifiedName.c_str());
-  addTo->Add(new LiteralExpression("/* CreateArrayFromParcel error " +
-                                   m_qualifiedName + " */"));
-}
-
-void Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                               Variable* parcel, Variable**) const {
-  fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", __FILE__,
-          __LINE__, m_qualifiedName.c_str());
-  addTo->Add(new LiteralExpression("/* ReadArrayFromParcel error " +
-                                   m_qualifiedName + " */"));
-}
-
 Expression* Type::BuildWriteToParcelFlags(int flags) const {
   if (flags == 0) {
     return new LiteralExpression("0");
@@ -127,10 +103,10 @@
                      const string& readArrayParcel)
     : Type(types, name, ValidatableType::KIND_BUILT_IN, true, false),
       m_marshallParcel(marshallParcel),
-      m_unmarshallParcel(unmarshallParcel),
-      m_writeArrayParcel(writeArrayParcel),
-      m_createArrayParcel(createArrayParcel),
-      m_readArrayParcel(readArrayParcel) {}
+      m_unmarshallParcel(unmarshallParcel) {
+  m_array_type.reset(new BasicArrayType(types, name, writeArrayParcel,
+                                        createArrayParcel, readArrayParcel));
+}
 
 void BasicType::WriteToParcel(StatementBlock* addTo, Variable* v,
                               Variable* parcel, int flags) const {
@@ -142,17 +118,28 @@
   addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
 }
 
-void BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+BasicArrayType::BasicArrayType(const JavaTypeNamespace* types,
+                               const string& name,
+                               const string& writeArrayParcel,
+                               const string& createArrayParcel,
+                               const string& readArrayParcel)
+    : Type(types, name, ValidatableType::KIND_BUILT_IN, true, false),
+      m_writeArrayParcel(writeArrayParcel),
+      m_createArrayParcel(createArrayParcel),
+      m_readArrayParcel(readArrayParcel) {}
+
+
+void BasicArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                    Variable* parcel, int flags) const {
   addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
 }
 
-void BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+void BasicArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
                                       Variable* parcel, Variable**) const {
   addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
 }
 
-void BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+void BasicArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable**) const {
   addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
 }
@@ -161,7 +148,9 @@
 
 FileDescriptorType::FileDescriptorType(const JavaTypeNamespace* types)
     : Type(types, "java.io", "FileDescriptor", ValidatableType::KIND_BUILT_IN,
-           true, false) {}
+           true, false) {
+    m_array_type.reset(new FileDescriptorArrayType(types));
+}
 
 void FileDescriptorType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                        Variable* parcel, int flags) const {
@@ -173,17 +162,21 @@
   addTo->Add(new Assignment(v, new MethodCall(parcel, "readRawFileDescriptor")));
 }
 
-void FileDescriptorType::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+FileDescriptorArrayType::FileDescriptorArrayType(const JavaTypeNamespace* types)
+    : Type(types, "java.io", "FileDescriptor", ValidatableType::KIND_BUILT_IN,
+           true, true) {}
+
+void FileDescriptorArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                             Variable* parcel, int flags) const {
   addTo->Add(new MethodCall(parcel, "writeRawFileDescriptorArray", 1, v));
 }
 
-void FileDescriptorType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+void FileDescriptorArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
                                                Variable* parcel, Variable**) const {
   addTo->Add(new Assignment(v, new MethodCall(parcel, "createRawFileDescriptorArray")));
 }
 
-void FileDescriptorType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+void FileDescriptorArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                                              Variable* parcel, Variable**) const {
   addTo->Add(new MethodCall(parcel, "readRawFileDescriptorArray", 1, v));
 }
@@ -191,7 +184,9 @@
 // ================================================================
 
 BooleanType::BooleanType(const JavaTypeNamespace* types)
-    : Type(types, "boolean", ValidatableType::KIND_BUILT_IN, true, false) {}
+    : Type(types, "boolean", ValidatableType::KIND_BUILT_IN, true, false) {
+    m_array_type.reset(new BooleanArrayType(types));
+}
 
 void BooleanType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                 Variable* parcel, int flags) const {
@@ -207,17 +202,20 @@
                                        new MethodCall(parcel, "readInt"))));
 }
 
-void BooleanType::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+BooleanArrayType::BooleanArrayType(const JavaTypeNamespace* types)
+    : Type(types, "boolean", ValidatableType::KIND_BUILT_IN, true, true) {}
+
+void BooleanArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                      Variable* parcel, int flags) const {
   addTo->Add(new MethodCall(parcel, "writeBooleanArray", 1, v));
 }
 
-void BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+void BooleanArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
                                         Variable* parcel, Variable**) const {
   addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
 }
 
-void BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+void BooleanArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                                       Variable* parcel, Variable**) const {
   addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
 }
@@ -225,7 +223,9 @@
 // ================================================================
 
 CharType::CharType(const JavaTypeNamespace* types)
-    : Type(types, "char", ValidatableType::KIND_BUILT_IN, true, false) {}
+    : Type(types, "char", ValidatableType::KIND_BUILT_IN, true, false) {
+    m_array_type.reset(new CharArrayType(types));
+}
 
 void CharType::WriteToParcel(StatementBlock* addTo, Variable* v,
                              Variable* parcel, int flags) const {
@@ -238,17 +238,20 @@
   addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
 }
 
-void CharType::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+CharArrayType::CharArrayType(const JavaTypeNamespace* types)
+    : Type(types, "char", ValidatableType::KIND_BUILT_IN, true, true) {}
+
+void CharArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                   Variable* parcel, int flags) const {
   addTo->Add(new MethodCall(parcel, "writeCharArray", 1, v));
 }
 
-void CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+void CharArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
                                      Variable* parcel, Variable**) const {
   addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
 }
 
-void CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+void CharArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                                    Variable* parcel, Variable**) const {
   addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
 }
@@ -257,7 +260,9 @@
 
 StringType::StringType(const JavaTypeNamespace* types)
     : Type(types, "java.lang", "String", ValidatableType::KIND_BUILT_IN,
-           true, false) {}
+           true, false) {
+    m_array_type.reset(new StringArrayType(types));
+}
 
 string StringType::CreatorName() const {
   return "android.os.Parcel.STRING_CREATOR";
@@ -273,17 +278,25 @@
   addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
 }
 
-void StringType::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+StringArrayType::StringArrayType(const JavaTypeNamespace* types)
+    : Type(types, "java.lang", "String", ValidatableType::KIND_BUILT_IN,
+           true, true) {}
+
+string StringArrayType::CreatorName() const {
+  return "android.os.Parcel.STRING_CREATOR";
+}
+
+void StringArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, int flags) const {
   addTo->Add(new MethodCall(parcel, "writeStringArray", 1, v));
 }
 
-void StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+void StringArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
                                        Variable* parcel, Variable**) const {
   addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
 }
 
-void StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+void StringArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                                      Variable* parcel, Variable**) const {
   addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
 }
@@ -379,7 +392,9 @@
 
 IBinderType::IBinderType(const JavaTypeNamespace* types)
     : Type(types, "android.os", "IBinder", ValidatableType::KIND_BUILT_IN,
-           true, false) {}
+           true, false) {
+  m_array_type.reset(new IBinderArrayType(types));
+}
 
 void IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                 Variable* parcel, int flags) const {
@@ -391,17 +406,21 @@
   addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
 }
 
-void IBinderType::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+IBinderArrayType::IBinderArrayType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "IBinder", ValidatableType::KIND_BUILT_IN,
+           true, true) {}
+
+void IBinderArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                      Variable* parcel, int flags) const {
   addTo->Add(new MethodCall(parcel, "writeBinderArray", 1, v));
 }
 
-void IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+void IBinderArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
                                         Variable* parcel, Variable**) const {
   addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
 }
 
-void IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+void IBinderArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                                       Variable* parcel, Variable**) const {
   addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
 }
@@ -557,7 +576,11 @@
     : Type(types, package, name,
            builtIn ? ValidatableType::KIND_BUILT_IN
                    : ValidatableType::KIND_PARCELABLE,
-           canWriteToParcel, true, declFile, declLine) {}
+           canWriteToParcel, true, declFile, declLine) {
+  m_array_type.reset(new UserDataArrayType(types, package, name, builtIn,
+                                           canWriteToParcel, declFile,
+                                           declLine));
+}
 
 string UserDataType::CreatorName() const {
   return QualifiedName() + ".CREATOR";
@@ -619,20 +642,33 @@
   addTo->Add(ifpart);
 }
 
-void UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v,
+UserDataArrayType::UserDataArrayType(const JavaTypeNamespace* types,
+                           const string& package, const string& name,
+                           bool builtIn, bool canWriteToParcel,
+                           const string& declFile, int declLine)
+    : Type(types, package, name,
+           builtIn ? ValidatableType::KIND_BUILT_IN
+                   : ValidatableType::KIND_PARCELABLE,
+           canWriteToParcel, true, declFile, declLine) {}
+
+string UserDataArrayType::CreatorName() const {
+  return QualifiedName() + ".CREATOR";
+}
+
+void UserDataArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
                                       Variable* parcel, int flags) const {
   addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
                             BuildWriteToParcelFlags(flags)));
 }
 
-void UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+void UserDataArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
                                          Variable* parcel, Variable**) const {
   string creator = v->type->QualifiedName() + ".CREATOR";
   addTo->Add(new Assignment(v, new MethodCall(parcel, "createTypedArray", 1,
                                               new LiteralExpression(creator))));
 }
 
-void UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
+void UserDataArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                                        Variable* parcel, Variable**) const {
   string creator = v->type->QualifiedName() + ".CREATOR";
   addTo->Add(new MethodCall(parcel, "readTypedArray", 2, v,
@@ -644,11 +680,13 @@
 InterfaceType::InterfaceType(const JavaTypeNamespace* types,
                              const string& package, const string& name,
                              bool builtIn, bool oneway, const string& declFile,
-                             int declLine)
+                             int declLine, const Type* stub, const Type* proxy)
     : Type(types, package, name, builtIn ? ValidatableType::KIND_BUILT_IN
                                          : ValidatableType::KIND_INTERFACE,
            true, false, declFile, declLine),
-      m_oneway(oneway) {}
+      m_oneway(oneway),
+      stub_(stub),
+      proxy_(proxy) {}
 
 bool InterfaceType::OneWay() const { return m_oneway; }
 
@@ -840,9 +878,6 @@
 bool JavaTypeNamespace::AddBinderType(const AidlInterface& b,
                                       const std::string& filename) {
   // for interfaces, add the stub, proxy, and interface types.
-  Type* type =
-      new InterfaceType(this, b.GetPackage(), b.GetName(), false,
-                        b.IsOneway(), filename, b.GetLine());
   Type* stub = new Type(this, b.GetPackage(),
                         b.GetName() + ".Stub", ValidatableType::KIND_GENERATED,
                         false, false, filename, b.GetLine());
@@ -850,6 +885,9 @@
                          b.GetName() + ".Stub.Proxy",
                          ValidatableType::KIND_GENERATED,
                          false, false, filename, b.GetLine());
+  Type* type =
+      new InterfaceType(this, b.GetPackage(), b.GetName(), false,
+                        b.IsOneway(), filename, b.GetLine(), stub, proxy);
 
   bool success = true;
   success &= Add(type);
diff --git a/type_java.h b/type_java.h
index b8a1d09..33832e9 100644
--- a/type_java.h
+++ b/type_java.h
@@ -44,10 +44,11 @@
        const string& declFile = "", int declLine = -1);
   virtual ~Type() = default;
 
-  bool CanBeArray() const override { return false; }
   bool CanBeOutParameter() const override { return m_canBeOut; }
   bool CanWriteToParcel() const override { return m_canWriteToParcel; }
 
+  const ValidatableType* ArrayType() const override { return m_array_type.get(); }
+
   inline string Package() const { return m_package; }
   virtual string CreatorName() const;
   virtual string InstantiableName() const;
@@ -59,19 +60,13 @@
   virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
                               Variable* parcel, Variable** cl) const;
 
-
-  virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                  Variable* parcel, int flags) const;
-  virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                     Variable* parcel, Variable** cl) const;
-  virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                   Variable* parcel, Variable** cl) const;
-
  protected:
   Expression* BuildWriteToParcelFlags(int flags) const;
 
   const JavaTypeNamespace* m_types;
 
+  std::unique_ptr<Type> m_array_type;
+
  private:
   Type();
   Type(const Type&);
@@ -84,6 +79,26 @@
   bool m_canBeOut;
 };
 
+class BasicArrayType : public Type {
+ public:
+  BasicArrayType(const JavaTypeNamespace* types, const string& name,
+                 const string& writeArrayParcel,
+                 const string& createArrayParcel,
+                 const string& readArrayParcel);
+
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                        Variable** cl) const override;
+  void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                      Variable** cl) const override;
+
+ private:
+  string m_writeArrayParcel;
+  string m_createArrayParcel;
+  string m_readArrayParcel;
+};
+
 class BasicType : public Type {
  public:
   BasicType(const JavaTypeNamespace* types, const string& name,
@@ -96,21 +111,21 @@
   void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                         Variable** cl) const override;
 
-  bool CanBeArray() const override { return true; }
-
-  void WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                          int flags) const override;
-  void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                             Variable* parcel, Variable** cl) const override;
-  void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                           Variable** cl) const override;
-
  private:
   string m_marshallParcel;
   string m_unmarshallParcel;
-  string m_writeArrayParcel;
-  string m_createArrayParcel;
-  string m_readArrayParcel;
+};
+
+class FileDescriptorArrayType : public Type {
+ public:
+  FileDescriptorArrayType(const JavaTypeNamespace* types);
+
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v,
+                        Variable* parcel, Variable** cl) const override;
+  void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                      Variable** cl) const override;
 };
 
 class FileDescriptorType : public Type {
@@ -121,15 +136,18 @@
                      int flags) const override;
   void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                         Variable** cl) const override;
+};
 
-  bool CanBeArray() const override { return true; }
+class BooleanArrayType : public Type {
+ public:
+  BooleanArrayType(const JavaTypeNamespace* types);
 
-  void WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                          int flags) const override;
-  void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                             Variable* parcel, Variable** cl) const override;
-  void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                           Variable** cl) const override;
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v,
+                        Variable* parcel, Variable** cl) const override;
+  void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                      Variable** cl) const override;
 };
 
 class BooleanType : public Type {
@@ -140,15 +158,18 @@
                      int flags) const override;
   void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                         Variable** cl) const override;
+};
 
-  bool CanBeArray() const override { return true; }
+class CharArrayType : public Type {
+ public:
+  CharArrayType(const JavaTypeNamespace* types);
 
-  void WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                          int flags) const override;
-  void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                             Variable* parcel, Variable** cl) const override;
-  void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                           Variable** cl) const override;
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v,
+                        Variable* parcel, Variable** cl) const override;
+  void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                      Variable** cl) const override;
 };
 
 class CharType : public Type {
@@ -159,15 +180,20 @@
                      int flags) const override;
   void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                         Variable** cl) const override;
+};
 
-  bool CanBeArray() const override { return true; }
+class StringArrayType : public Type {
+ public:
+  StringArrayType(const JavaTypeNamespace* types);
 
-  void WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                          int flags) const override;
-  void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                             Variable* parcel, Variable** cl) const override;
-  void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                           Variable** cl) const override;
+  string CreatorName() const override;
+
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v,
+                        Variable* parcel, Variable** cl) const override;
+  void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                      Variable** cl) const override;
 };
 
 class StringType : public Type {
@@ -180,15 +206,6 @@
                      int flags) const override;
   void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                         Variable** cl) const override;
-
-  bool CanBeArray() const override { return true; }
-
-  void WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                          int flags) const override;
-  void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                             Variable* parcel, Variable** cl) const override;
-  void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                           Variable** cl) const override;
 };
 
 class CharSequenceType : public Type {
@@ -223,6 +240,18 @@
                         Variable** cl) const override;
 };
 
+class IBinderArrayType : public Type {
+ public:
+  IBinderArrayType(const JavaTypeNamespace* types);
+
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v,
+                        Variable* parcel, Variable** cl) const override;
+  void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                      Variable** cl) const override;
+};
+
 class IBinderType : public Type {
  public:
   IBinderType(const JavaTypeNamespace* types);
@@ -231,13 +260,6 @@
                      int flags) const override;
   void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                         Variable** cl) const override;
-
-  void WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                          int flags) const override;
-  void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                             Variable* parcel, Variable** cl) const override;
-  void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                           Variable** cl) const override;
 };
 
 class IInterfaceType : public Type {
@@ -316,6 +338,22 @@
                       Variable** cl) const override;
 };
 
+class UserDataArrayType : public Type {
+ public:
+  UserDataArrayType(const JavaTypeNamespace* types, const string& package,
+                    const string& name, bool builtIn, bool canWriteToParcel,
+                    const string& declFile = "", int declLine = -1);
+
+  string CreatorName() const override;
+
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v,
+                        Variable* parcel, Variable** cl) const override;
+  void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                      Variable** cl) const override;
+};
+
 class UserDataType : public Type {
  public:
   UserDataType(const JavaTypeNamespace* types, const string& package,
@@ -330,22 +368,14 @@
                         Variable** cl) const override;
   void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                       Variable** cl) const override;
-
-  bool CanBeArray() const override { return true; }
-
-  void WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                          int flags) const override;
-  void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                             Variable* parcel, Variable** cl) const override;
-  void ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
-                           Variable** cl) const override;
 };
 
 class InterfaceType : public Type {
  public:
   InterfaceType(const JavaTypeNamespace* types, const string& package,
                 const string& name, bool builtIn, bool oneway,
-                const string& declFile, int declLine);
+                const string& declFile, int declLine, const Type* stub,
+                const Type* proxy);
 
   bool OneWay() const;
 
@@ -353,9 +383,13 @@
                      int flags) const override;
   void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
                         Variable** cl) const override;
+  const Type* GetStub() const { return stub_; }
+  const Type* GetProxy() const { return proxy_; }
 
  private:
   bool m_oneway;
+  const Type* stub_;
+  const Type* proxy_;
 };
 
 class ClassLoaderType : public Type {
diff --git a/type_java_unittest.cpp b/type_java_unittest.cpp
index ee4397f..4adaa47 100644
--- a/type_java_unittest.cpp
+++ b/type_java_unittest.cpp
@@ -36,26 +36,26 @@
 };
 
 TEST_F(JavaTypeNamespaceTest, HasSomeBasicTypes) {
-  EXPECT_NE(types_.Find("void"), nullptr);
-  EXPECT_NE(types_.Find("int"), nullptr);
-  EXPECT_NE(types_.Find("String"), nullptr);
+  EXPECT_TRUE(types_.HasType("void"));
+  EXPECT_TRUE(types_.HasType("int"));
+  EXPECT_TRUE(types_.HasType("String"));
 }
 
 TEST_F(JavaTypeNamespaceTest, ContainerTypeCreation) {
   // We start with no knowledge of parcelables or lists of them.
-  EXPECT_EQ(types_.Find("Foo"), nullptr);
-  EXPECT_EQ(types_.Find("List<Foo>"), nullptr);
+  EXPECT_FALSE(types_.HasType("Foo"));
+  EXPECT_FALSE(types_.HasType("List<Foo>"));
   unique_ptr<AidlParcelable> parcelable(
       new AidlParcelable(new AidlQualifiedName("Foo", ""), 0, {"a", "goog"}));
   // Add the parcelable type we care about.
   EXPECT_TRUE(types_.AddParcelableType(*parcelable.get(), __FILE__));
   // Now we can find the parcelable type, but not the List of them.
-  EXPECT_NE(types_.Find("Foo"), nullptr);
-  EXPECT_EQ(types_.Find("List<Foo>"), nullptr);
+  EXPECT_TRUE(types_.HasType("Foo"));
+  EXPECT_FALSE(types_.HasType("List<Foo>"));
   // But after we add the list explicitly...
   EXPECT_TRUE(types_.MaybeAddContainerType("List<Foo>"));
   // This should work.
-  EXPECT_NE(types_.Find("List<Foo>"), nullptr);
+  EXPECT_TRUE(types_.HasType("List<Foo>"));
 }
 
 }  // namespace java
diff --git a/type_namespace.h b/type_namespace.h
index f135d9f..453a1c2 100644
--- a/type_namespace.h
+++ b/type_namespace.h
@@ -42,10 +42,12 @@
                   const std::string& decl_file, int decl_line);
   virtual ~ValidatableType() = default;
 
-  virtual bool CanBeArray() const = 0;
+  virtual bool CanBeArray() const { return ArrayType() != nullptr; }
   virtual bool CanBeOutParameter() const = 0;
   virtual bool CanWriteToParcel() const = 0;
 
+  virtual const ValidatableType* ArrayType() const = 0;
+
   // Name() returns the short name of an object (without package qualifiers).
   virtual std::string Name() const { return type_name_; }
   // QualifiedName() returns the canonical AIDL type, with packages.
@@ -110,14 +112,14 @@
       std::vector<std::string>* container_class,
       std::vector<std::string>* contained_type_names) const;
 
- protected:
-  TypeNamespace() = default;
-  virtual ~TypeNamespace() = default;
-
   // Get a pointer to an existing type.
   virtual const ValidatableType* GetValidatableType(
       const std::string& name) const = 0;
 
+ protected:
+  TypeNamespace() = default;
+  virtual ~TypeNamespace() = default;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
 };
@@ -132,11 +134,11 @@
   // name, and then class name (dropping package qualifiers).
   const T* Find(const std::string& name) const;
 
- protected:
-  bool Add(const T* type);
   const ValidatableType* GetValidatableType(
       const std::string& name) const override { return Find(name); }
 
+ protected:
+  bool Add(const T* type);
  private:
   std::vector<std::unique_ptr<const T>> types_;