Project import
diff --git a/aidl/Android.mk b/aidl/Android.mk
new file mode 100644
index 0000000..3c1463a
--- /dev/null
+++ b/aidl/Android.mk
@@ -0,0 +1,204 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+aidl_cflags := -Wall -Wextra -Werror
+aidl_static_libraries := libbase libcutils
+
+aidl_module_host_os := darwin linux windows
+ifdef BRILLO
+  aidl_module_host_os := darwin linux
+endif
+
+# Logic shared between aidl and its unittests
+include $(CLEAR_VARS)
+LOCAL_MODULE := libaidl-common
+LOCAL_MODULE_HOST_OS := $(aidl_module_host_os)
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CLANG_CFLAGS := $(aidl_cflags)
+# Tragically, the code is riddled with unused parameters.
+LOCAL_CLANG_CFLAGS += -Wno-unused-parameter
+# yacc dumps a lot of code *just in case*.
+LOCAL_CLANG_CFLAGS += -Wno-unused-function
+LOCAL_CLANG_CFLAGS += -Wno-unneeded-internal-declaration
+# yacc is a tool from a more civilized age.
+LOCAL_CLANG_CFLAGS += -Wno-deprecated-register
+# yacc also has a habit of using char* over const char*.
+LOCAL_CLANG_CFLAGS += -Wno-writable-strings
+LOCAL_STATIC_LIBRARIES := $(aidl_static_libraries)
+
+LOCAL_SRC_FILES := \
+    aidl.cpp \
+    aidl_language.cpp \
+    aidl_language_l.ll \
+    aidl_language_y.yy \
+    ast_cpp.cpp \
+    ast_java.cpp \
+    code_writer.cpp \
+    generate_cpp.cpp \
+    generate_java.cpp \
+    generate_java_binder.cpp \
+    import_resolver.cpp \
+    line_reader.cpp \
+    io_delegate.cpp \
+    options.cpp \
+    type_cpp.cpp \
+    type_java.cpp \
+    type_namespace.cpp \
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# aidl executable
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl
+
+LOCAL_MODULE_HOST_OS := $(aidl_module_host_os)
+LOCAL_CFLAGS := $(aidl_cflags)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
+LOCAL_SRC_FILES := main_java.cpp
+LOCAL_STATIC_LIBRARIES := libaidl-common $(aidl_static_libraries)
+include $(BUILD_HOST_EXECUTABLE)
+
+# aidl-cpp executable
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl-cpp
+
+LOCAL_MODULE_HOST_OS := $(aidl_module_host_os)
+LOCAL_CFLAGS := $(aidl_cflags)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
+LOCAL_SRC_FILES := main_cpp.cpp
+LOCAL_STATIC_LIBRARIES := libaidl-common $(aidl_static_libraries)
+include $(BUILD_HOST_EXECUTABLE)
+
+# Unit tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_unittests
+LOCAL_MODULE_HOST_OS := darwin linux
+
+LOCAL_CFLAGS := $(aidl_cflags) -g -DUNIT_TEST
+# Tragically, the code is riddled with unused parameters.
+LOCAL_CLANG_CFLAGS := -Wno-unused-parameter
+LOCAL_SRC_FILES := \
+    aidl_unittest.cpp \
+    ast_cpp_unittest.cpp \
+    ast_java_unittest.cpp \
+    generate_cpp_unittest.cpp \
+    io_delegate_unittest.cpp \
+    options_unittest.cpp \
+    tests/end_to_end_tests.cpp \
+    tests/fake_io_delegate.cpp \
+    tests/main.cpp \
+    tests/test_data_example_interface.cpp \
+    tests/test_data_ping_responder.cpp \
+    tests/test_data_string_constants.cpp \
+    tests/test_util.cpp \
+    type_cpp_unittest.cpp \
+    type_java_unittest.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+    libaidl-common \
+    $(aidl_static_libraries) \
+    libgmock_host \
+
+LOCAL_LDLIBS_linux := -lrt
+include $(BUILD_HOST_NATIVE_TEST)
+
+#
+# Everything below here is used for integration testing of generated AIDL code.
+#
+aidl_integration_test_cflags := $(aidl_cflags) -Wunused-parameter
+aidl_integration_test_shared_libs := \
+    libbase \
+    libbinder \
+    liblog \
+    libutils
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libaidl-integration-test
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_CFLAGS := $(aidl_integration_test_cflags)
+LOCAL_SHARED_LIBRARIES := $(aidl_integration_test_shared_libs)
+LOCAL_AIDL_INCLUDES := \
+    system/tools/aidl/tests/ \
+    frameworks/native/aidl/binder
+LOCAL_SRC_FILES := \
+    tests/android/aidl/tests/ITestService.aidl \
+    tests/android/aidl/tests/INamedCallback.aidl \
+    tests/simple_parcelable.cpp
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_test_service
+LOCAL_CFLAGS := $(aidl_integration_test_cflags)
+LOCAL_SHARED_LIBRARIES := \
+    libaidl-integration-test \
+    $(aidl_integration_test_shared_libs)
+LOCAL_SRC_FILES := \
+    tests/aidl_test_service.cpp
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_test_client
+LOCAL_CFLAGS := $(aidl_integration_test_cflags)
+LOCAL_SHARED_LIBRARIES := \
+    libaidl-integration-test \
+    $(aidl_integration_test_shared_libs)
+LOCAL_SRC_FILES := \
+    tests/aidl_test_client.cpp \
+    tests/aidl_test_client_file_descriptors.cpp \
+    tests/aidl_test_client_parcelables.cpp \
+    tests/aidl_test_client_nullables.cpp \
+    tests/aidl_test_client_primitives.cpp \
+    tests/aidl_test_client_utf8_strings.cpp \
+    tests/aidl_test_client_service_exceptions.cpp
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_test_sentinel_searcher
+LOCAL_SRC_FILES := tests/aidl_test_sentinel_searcher.cpp
+LOCAL_CFLAGS := $(aidl_integration_test_cflags)
+include $(BUILD_EXECUTABLE)
+
+
+# aidl on its own doesn't need the framework, but testing native/java
+# compatibility introduces java dependencies.
+ifndef BRILLO
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := aidl_test_services
+# Turn off Java optimization tools to speed up our test iterations.
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := tests/java_app/AndroidManifest.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/tests/java_app/resources
+LOCAL_SRC_FILES := \
+    tests/android/aidl/tests/INamedCallback.aidl \
+    tests/android/aidl/tests/ITestService.aidl \
+    tests/java_app/src/android/aidl/tests/NullableTests.java \
+    tests/java_app/src/android/aidl/tests/SimpleParcelable.java \
+    tests/java_app/src/android/aidl/tests/TestFailException.java \
+    tests/java_app/src/android/aidl/tests/TestLogger.java \
+    tests/java_app/src/android/aidl/tests/TestServiceClient.java
+LOCAL_AIDL_INCLUDES := \
+    system/tools/aidl/tests/ \
+    frameworks/native/aidl/binder
+include $(BUILD_PACKAGE)
+
+endif  # not defined BRILLO
diff --git a/aidl/MODULE_LICENSE_APACHE2 b/aidl/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/aidl/MODULE_LICENSE_APACHE2
diff --git a/aidl/NOTICE b/aidl/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/aidl/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/aidl/aidl.cpp b/aidl/aidl.cpp
new file mode 100644
index 0000000..cd778fa
--- /dev/null
+++ b/aidl/aidl.cpp
@@ -0,0 +1,771 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl.h"
+
+#include <fcntl.h>
+#include <iostream>
+#include <map>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef _WIN32
+#include <io.h>
+#include <direct.h>
+#include <sys/stat.h>
+#endif
+
+#include <android-base/strings.h>
+
+#include "aidl_language.h"
+#include "generate_cpp.h"
+#include "generate_java.h"
+#include "import_resolver.h"
+#include "logging.h"
+#include "options.h"
+#include "os.h"
+#include "type_cpp.h"
+#include "type_java.h"
+#include "type_namespace.h"
+
+#ifndef O_BINARY
+#  define O_BINARY  0
+#endif
+
+using android::base::Join;
+using android::base::Split;
+using std::cerr;
+using std::endl;
+using std::map;
+using std::set;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace {
+
+// The following are gotten as the offset from the allowable id's between
+// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
+// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
+const int kMinUserSetMethodId = 0;
+const int kMaxUserSetMethodId = 16777214;
+
+bool check_filename(const std::string& filename,
+                    const std::string& package,
+                    const std::string& name,
+                    unsigned line) {
+    const char* p;
+    string expected;
+    string fn;
+    size_t len;
+    bool valid = false;
+
+    if (!IoDelegate::GetAbsolutePath(filename, &fn)) {
+      return false;
+    }
+
+    if (!package.empty()) {
+        expected = package;
+        expected += '.';
+    }
+
+    len = expected.length();
+    for (size_t i=0; i<len; i++) {
+        if (expected[i] == '.') {
+            expected[i] = OS_PATH_SEPARATOR;
+        }
+    }
+
+    expected.append(name, 0, name.find('.'));
+
+    expected += ".aidl";
+
+    len = fn.length();
+    valid = (len >= expected.length());
+
+    if (valid) {
+        p = fn.c_str() + (len - expected.length());
+
+#ifdef _WIN32
+        if (OS_PATH_SEPARATOR != '/') {
+            // Input filename under cygwin most likely has / separators
+            // whereas the expected string uses \\ separators. Adjust
+            // them accordingly.
+          for (char *c = const_cast<char *>(p); *c; ++c) {
+                if (*c == '/') *c = OS_PATH_SEPARATOR;
+            }
+        }
+#endif
+
+        // aidl assumes case-insensitivity on Mac Os and Windows.
+#if defined(__linux__)
+        valid = (expected == p);
+#else
+        valid = !strcasecmp(expected.c_str(), p);
+#endif
+    }
+
+    if (!valid) {
+        fprintf(stderr, "%s:%d interface %s should be declared in a file"
+                " called %s.\n",
+                filename.c_str(), line, name.c_str(), expected.c_str());
+    }
+
+    return valid;
+}
+
+bool check_filenames(const std::string& filename, const AidlDocument* doc) {
+  if (!doc)
+    return true;
+
+  const AidlInterface* interface = doc->GetInterface();
+
+  if (interface) {
+    return check_filename(filename, interface->GetPackage(),
+                          interface->GetName(), interface->GetLine());
+  }
+
+  bool success = true;
+
+  for (const auto& item : doc->GetParcelables()) {
+    success &= check_filename(filename, item->GetPackage(), item->GetName(),
+                              item->GetLine());
+  }
+
+  return success;
+}
+
+bool gather_types(const std::string& filename,
+                  const AidlDocument* doc,
+                  TypeNamespace* types) {
+  bool success = true;
+
+  const AidlInterface* interface = doc->GetInterface();
+
+  if (interface)
+    return types->AddBinderType(*interface, filename);
+
+  for (const auto& item : doc->GetParcelables()) {
+    success &= types->AddParcelableType(*item, filename);
+  }
+
+  return success;
+}
+
+int check_types(const string& filename,
+                const AidlInterface* c,
+                TypeNamespace* types) {
+  int err = 0;
+
+  if (c->IsUtf8() && c->IsUtf8InCpp()) {
+    cerr << filename << ":" << c->GetLine()
+         << "Interface cannot be marked as both @utf8 and @utf8InCpp";
+    err = 1;
+  }
+
+  // Has to be a pointer due to deleting copy constructor. No idea why.
+  map<string, const AidlMethod*> method_names;
+  for (const auto& m : c->GetMethods()) {
+    bool oneway = m->IsOneway() || c->IsOneway();
+
+    if (!types->MaybeAddContainerType(m->GetType())) {
+      err = 1;  // return type is invalid
+    }
+
+    const ValidatableType* return_type =
+        types->GetReturnType(m->GetType(), filename, *c);
+
+    if (!return_type) {
+      err = 1;
+    }
+
+    m->GetMutableType()->SetLanguageType(return_type);
+
+    if (oneway && m->GetType().GetName() != "void") {
+        cerr << filename << ":" << m->GetLine()
+            << " oneway method '" << m->GetName() << "' cannot return a value"
+            << endl;
+        err = 1;
+    }
+
+    int index = 1;
+    for (const auto& arg : m->GetArguments()) {
+      if (!types->MaybeAddContainerType(arg->GetType())) {
+        err = 1;
+      }
+
+      const ValidatableType* arg_type =
+          types->GetArgType(*arg, index, filename, *c);
+
+      if (!arg_type) {
+        err = 1;
+      }
+
+      arg->GetMutableType()->SetLanguageType(arg_type);
+
+      if (oneway && arg->IsOut()) {
+        cerr << filename << ":" << m->GetLine()
+            << " oneway method '" << m->GetName()
+            << "' cannot have out parameters" << endl;
+        err = 1;
+      }
+    }
+
+    auto it = method_names.find(m->GetName());
+    // prevent duplicate methods
+    if (it == method_names.end()) {
+      method_names[m->GetName()] = m.get();
+    } else {
+      cerr << filename << ":" << m->GetLine()
+           << " attempt to redefine method " << m->GetName() << "," << endl
+           << filename << ":" << it->second->GetLine()
+           << "    previously defined here." << endl;
+      err = 1;
+    }
+  }
+  return err;
+}
+
+void write_common_dep_file(const string& output_file,
+                           const vector<string>& aidl_sources,
+                           CodeWriter* writer) {
+  // Encode that the output file depends on aidl input files.
+  writer->Write("%s : \\\n", output_file.c_str());
+  writer->Write("  %s", Join(aidl_sources, " \\\n  ").c_str());
+  writer->Write("\n\n");
+
+  // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
+  // has been deleted, moved or renamed in incremental build.
+  for (const auto& src : aidl_sources) {
+    writer->Write("%s :\n", src.c_str());
+  }
+}
+
+bool write_java_dep_file(const JavaOptions& options,
+                         const vector<unique_ptr<AidlImport>>& imports,
+                         const IoDelegate& io_delegate,
+                         const string& output_file_name) {
+  string dep_file_name = options.DependencyFilePath();
+  if (dep_file_name.empty()) {
+    return true;  // nothing to do
+  }
+  CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
+  if (!writer) {
+    LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
+    return false;
+  }
+
+  vector<string> source_aidl = {options.input_file_name_};
+  for (const auto& import : imports) {
+    if (!import->GetFilename().empty()) {
+      source_aidl.push_back(import->GetFilename());
+    }
+  }
+
+  write_common_dep_file(output_file_name, source_aidl, writer.get());
+
+  return true;
+}
+
+bool write_cpp_dep_file(const CppOptions& options,
+                        const AidlInterface& interface,
+                        const vector<unique_ptr<AidlImport>>& imports,
+                        const IoDelegate& io_delegate) {
+  using ::android::aidl::cpp::HeaderFile;
+  using ::android::aidl::cpp::ClassNames;
+
+  string dep_file_name = options.DependencyFilePath();
+  if (dep_file_name.empty()) {
+    return true;  // nothing to do
+  }
+  CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
+  if (!writer) {
+    LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
+    return false;
+  }
+
+  vector<string> source_aidl = {options.InputFileName()};
+  for (const auto& import : imports) {
+    if (!import->GetFilename().empty()) {
+      source_aidl.push_back(import->GetFilename());
+    }
+  }
+
+  vector<string> headers;
+  for (ClassNames c : {ClassNames::CLIENT,
+                       ClassNames::SERVER,
+                       ClassNames::INTERFACE}) {
+    headers.push_back(options.OutputHeaderDir() + '/' +
+                      HeaderFile(interface, c, false /* use_os_sep */));
+  }
+
+  write_common_dep_file(options.OutputCppFilePath(), source_aidl, writer.get());
+  writer->Write("\n");
+
+  // Generated headers also depend on the source aidl files.
+  writer->Write("%s : \\\n    %s\n", Join(headers, " \\\n    ").c_str(),
+                Join(source_aidl, " \\\n    ").c_str());
+
+  return true;
+}
+
+string generate_outputFileName(const JavaOptions& options,
+                               const AidlInterface& interface) {
+    const string& name = interface.GetName();
+    string package = interface.GetPackage();
+    string result;
+
+    // create the path to the destination folder based on the
+    // interface package name
+    result = options.output_base_folder_;
+    result += OS_PATH_SEPARATOR;
+
+    string packageStr = package;
+    size_t len = packageStr.length();
+    for (size_t i=0; i<len; i++) {
+        if (packageStr[i] == '.') {
+            packageStr[i] = OS_PATH_SEPARATOR;
+        }
+    }
+
+    result += packageStr;
+
+    // add the filename by replacing the .aidl extension to .java
+    result += OS_PATH_SEPARATOR;
+    result.append(name, 0, name.find('.'));
+    result += ".java";
+
+    return result;
+}
+
+int check_and_assign_method_ids(const char * filename,
+                                const std::vector<std::unique_ptr<AidlMethod>>& items) {
+    // Check whether there are any methods with manually assigned id's and any that are not.
+    // Either all method id's must be manually assigned or all of them must not.
+    // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
+    set<int> usedIds;
+    bool hasUnassignedIds = false;
+    bool hasAssignedIds = false;
+    for (const auto& item : items) {
+        if (item->HasId()) {
+            hasAssignedIds = true;
+            // Ensure that the user set id is not duplicated.
+            if (usedIds.find(item->GetId()) != usedIds.end()) {
+                // We found a duplicate id, so throw an error.
+                fprintf(stderr,
+                        "%s:%d Found duplicate method id (%d) for method: %s\n",
+                        filename, item->GetLine(),
+                        item->GetId(), item->GetName().c_str());
+                return 1;
+            }
+            // Ensure that the user set id is within the appropriate limits
+            if (item->GetId() < kMinUserSetMethodId ||
+                    item->GetId() > kMaxUserSetMethodId) {
+                fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
+                        filename, item->GetLine(),
+                        item->GetId(), item->GetName().c_str());
+                fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
+                        kMinUserSetMethodId, kMaxUserSetMethodId);
+                return 1;
+            }
+            usedIds.insert(item->GetId());
+        } else {
+            hasUnassignedIds = true;
+        }
+        if (hasAssignedIds && hasUnassignedIds) {
+            fprintf(stderr,
+                    "%s: You must either assign id's to all methods or to none of them.\n",
+                    filename);
+            return 1;
+        }
+    }
+
+    // In the case that all methods have unassigned id's, set a unique id for them.
+    if (hasUnassignedIds) {
+        int newId = 0;
+        for (const auto& item : items) {
+            item->SetId(newId++);
+        }
+    }
+
+    // success
+    return 0;
+}
+
+bool validate_constants(const AidlInterface& interface) {
+  bool success = true;
+  set<string> names;
+  for (const std::unique_ptr<AidlIntConstant>& int_constant :
+       interface.GetIntConstants()) {
+    if (names.count(int_constant->GetName()) > 0) {
+      LOG(ERROR) << "Found duplicate constant name '" << int_constant->GetName()
+                 << "'";
+      success = false;
+    }
+    names.insert(int_constant->GetName());
+    // We've logged an error message for this on object construction.
+    success = success && int_constant->IsValid();
+  }
+  for (const std::unique_ptr<AidlStringConstant>& string_constant :
+       interface.GetStringConstants()) {
+    if (names.count(string_constant->GetName()) > 0) {
+      LOG(ERROR) << "Found duplicate constant name '" << string_constant->GetName()
+                 << "'";
+      success = false;
+    }
+    names.insert(string_constant->GetName());
+    // We've logged an error message for this on object construction.
+    success = success && string_constant->IsValid();
+  }
+  return success;
+}
+
+// TODO: Remove this in favor of using the YACC parser b/25479378
+bool ParsePreprocessedLine(const string& line, string* decl,
+                           vector<string>* package, string* class_name) {
+  // erase all trailing whitespace and semicolons
+  const size_t end = line.find_last_not_of(" ;\t");
+  if (end == string::npos) {
+    return false;
+  }
+  if (line.rfind(';', end) != string::npos) {
+    return false;
+  }
+
+  decl->clear();
+  string type;
+  vector<string> pieces = Split(line.substr(0, end + 1), " \t");
+  for (const string& piece : pieces) {
+    if (piece.empty()) {
+      continue;
+    }
+    if (decl->empty()) {
+      *decl = std::move(piece);
+    } else if (type.empty()) {
+      type = std::move(piece);
+    } else {
+      return false;
+    }
+  }
+
+  // Note that this logic is absolutely wrong.  Given a parcelable
+  // org.some.Foo.Bar, the class name is Foo.Bar, but this code will claim that
+  // the class is just Bar.  However, this was the way it was done in the past.
+  //
+  // See b/17415692
+  size_t dot_pos = type.rfind('.');
+  if (dot_pos != string::npos) {
+    *class_name = type.substr(dot_pos + 1);
+    *package = Split(type.substr(0, dot_pos), ".");
+  } else {
+    *class_name = type;
+    package->clear();
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace internals {
+
+bool parse_preprocessed_file(const IoDelegate& io_delegate,
+                             const string& filename, TypeNamespace* types) {
+  bool success = true;
+  unique_ptr<LineReader> line_reader = io_delegate.GetLineReader(filename);
+  if (!line_reader) {
+    LOG(ERROR) << "cannot open preprocessed file: " << filename;
+    success = false;
+    return success;
+  }
+
+  string line;
+  unsigned lineno = 1;
+  for ( ; line_reader->ReadLine(&line); ++lineno) {
+    if (line.empty() || line.compare(0, 2, "//") == 0) {
+      // skip comments and empty lines
+      continue;
+    }
+
+    string decl;
+    vector<string> package;
+    string class_name;
+    if (!ParsePreprocessedLine(line, &decl, &package, &class_name)) {
+      success = false;
+      break;
+    }
+
+    if (decl == "parcelable") {
+      AidlParcelable doc(new AidlQualifiedName(class_name, ""),
+                         lineno, package);
+      types->AddParcelableType(doc, filename);
+    } else if (decl == "interface") {
+      auto temp = new std::vector<std::unique_ptr<AidlMember>>();
+      AidlInterface doc(class_name, lineno, "", false, temp, package);
+      types->AddBinderType(doc, filename);
+    } else {
+      success = false;
+      break;
+    }
+  }
+  if (!success) {
+    LOG(ERROR) << filename << ':' << lineno
+               << " malformed preprocessed file line: '" << line << "'";
+  }
+
+  return success;
+}
+
+AidlError load_and_validate_aidl(
+    const std::vector<std::string>& preprocessed_files,
+    const std::vector<std::string>& import_paths,
+    const std::string& input_file_name,
+    const IoDelegate& io_delegate,
+    TypeNamespace* types,
+    std::unique_ptr<AidlInterface>* returned_interface,
+    std::vector<std::unique_ptr<AidlImport>>* returned_imports) {
+  AidlError err = AidlError::OK;
+
+  std::map<AidlImport*,std::unique_ptr<AidlDocument>> docs;
+
+  // import the preprocessed file
+  for (const string& s : preprocessed_files) {
+    if (!parse_preprocessed_file(io_delegate, s, types)) {
+      err = AidlError::BAD_PRE_PROCESSED_FILE;
+    }
+  }
+  if (err != AidlError::OK) {
+    return err;
+  }
+
+  // parse the input file
+  Parser p{io_delegate};
+  if (!p.ParseFile(input_file_name)) {
+    return AidlError::PARSE_ERROR;
+  }
+
+  AidlDocument* parsed_doc = p.GetDocument();
+
+  unique_ptr<AidlInterface> interface(parsed_doc->ReleaseInterface());
+
+  if (!interface) {
+    LOG(ERROR) << "refusing to generate code from aidl file defining "
+                  "parcelable";
+    return AidlError::FOUND_PARCELABLE;
+  }
+
+  if (!check_filename(input_file_name.c_str(), interface->GetPackage(),
+                      interface->GetName(), interface->GetLine()) ||
+      !types->IsValidPackage(interface->GetPackage())) {
+    LOG(ERROR) << "Invalid package declaration '" << interface->GetPackage()
+               << "'";
+    return AidlError::BAD_PACKAGE;
+  }
+
+  // parse the imports of the input file
+  ImportResolver import_resolver{io_delegate, import_paths};
+  for (auto& import : p.GetImports()) {
+    if (types->HasImportType(*import)) {
+      // There are places in the Android tree where an import doesn't resolve,
+      // but we'll pick the type up through the preprocessed types.
+      // This seems like an error, but legacy support demands we support it...
+      continue;
+    }
+    string import_path = import_resolver.FindImportFile(import->GetNeededClass());
+    if (import_path.empty()) {
+      cerr << import->GetFileFrom() << ":" << import->GetLine()
+           << ": couldn't find import for class "
+           << import->GetNeededClass() << endl;
+      err = AidlError::BAD_IMPORT;
+      continue;
+    }
+    import->SetFilename(import_path);
+
+    Parser p{io_delegate};
+    if (!p.ParseFile(import->GetFilename())) {
+      cerr << "error while parsing import for class "
+           << import->GetNeededClass() << endl;
+      err = AidlError::BAD_IMPORT;
+      continue;
+    }
+
+    std::unique_ptr<AidlDocument> document(p.ReleaseDocument());
+    if (!check_filenames(import->GetFilename(), document.get()))
+      err = AidlError::BAD_IMPORT;
+    docs[import.get()] = std::move(document);
+  }
+  if (err != AidlError::OK) {
+    return err;
+  }
+
+  // gather the types that have been declared
+  if (!types->AddBinderType(*interface.get(), input_file_name)) {
+    err = AidlError::BAD_TYPE;
+  }
+
+  interface->SetLanguageType(types->GetInterfaceType(*interface));
+
+  for (const auto& import : p.GetImports()) {
+    // If we skipped an unresolved import above (see comment there) we'll have
+    // an empty bucket here.
+    const auto import_itr = docs.find(import.get());
+    if (import_itr == docs.cend()) {
+      continue;
+    }
+
+    if (!gather_types(import->GetFilename(), import_itr->second.get(), types)) {
+      err = AidlError::BAD_TYPE;
+    }
+  }
+
+  // check the referenced types in parsed_doc to make sure we've imported them
+  if (check_types(input_file_name, interface.get(), types) != 0) {
+    err = AidlError::BAD_TYPE;
+  }
+  if (err != AidlError::OK) {
+    return err;
+  }
+
+
+  // assign method ids and validate.
+  if (check_and_assign_method_ids(input_file_name.c_str(),
+                                  interface->GetMethods()) != 0) {
+    return AidlError::BAD_METHOD_ID;
+  }
+  if (!validate_constants(*interface)) {
+    return AidlError::BAD_CONSTANTS;
+  }
+
+  if (returned_interface)
+    *returned_interface = std::move(interface);
+
+  if (returned_imports)
+    p.ReleaseImports(returned_imports);
+
+  return AidlError::OK;
+}
+
+} // namespace internals
+
+int compile_aidl_to_cpp(const CppOptions& options,
+                        const IoDelegate& io_delegate) {
+  unique_ptr<AidlInterface> interface;
+  std::vector<std::unique_ptr<AidlImport>> imports;
+  unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace());
+  types->Init();
+  AidlError err = internals::load_and_validate_aidl(
+      std::vector<std::string>{},  // no preprocessed files
+      options.ImportPaths(),
+      options.InputFileName(),
+      io_delegate,
+      types.get(),
+      &interface,
+      &imports);
+  if (err != AidlError::OK) {
+    return 1;
+  }
+
+  if (!write_cpp_dep_file(options, *interface, imports, io_delegate)) {
+    return 1;
+  }
+
+  return (cpp::GenerateCpp(options, *types, *interface, io_delegate)) ? 0 : 1;
+}
+
+int compile_aidl_to_java(const JavaOptions& options,
+                         const IoDelegate& io_delegate) {
+  unique_ptr<AidlInterface> interface;
+  std::vector<std::unique_ptr<AidlImport>> imports;
+  unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
+  types->Init();
+  AidlError aidl_err = internals::load_and_validate_aidl(
+      options.preprocessed_files_,
+      options.import_paths_,
+      options.input_file_name_,
+      io_delegate,
+      types.get(),
+      &interface,
+      &imports);
+  if (aidl_err == AidlError::FOUND_PARCELABLE && !options.fail_on_parcelable_) {
+    // We aborted code generation because this file contains parcelables.
+    // However, we were not told to complain if we find parcelables.
+    // Just generate a dep file and exit quietly.  The dep file is for a legacy
+    // use case by the SDK.
+    write_java_dep_file(options, imports, io_delegate, "");
+    return 0;
+  }
+  if (aidl_err != AidlError::OK) {
+    return 1;
+  }
+
+  string output_file_name = options.output_file_name_;
+  // if needed, generate the output file name from the base folder
+  if (output_file_name.empty() && !options.output_base_folder_.empty()) {
+    output_file_name = generate_outputFileName(options, *interface);
+  }
+
+  // make sure the folders of the output file all exists
+  if (!io_delegate.CreatePathForFile(output_file_name)) {
+    return 1;
+  }
+
+  if (!write_java_dep_file(options, imports, io_delegate, output_file_name)) {
+    return 1;
+  }
+
+  return generate_java(output_file_name, options.input_file_name_.c_str(),
+                       interface.get(), types.get(), io_delegate);
+}
+
+bool preprocess_aidl(const JavaOptions& options,
+                     const IoDelegate& io_delegate) {
+  unique_ptr<CodeWriter> writer =
+      io_delegate.GetCodeWriter(options.output_file_name_);
+
+  for (const auto& file : options.files_to_preprocess_) {
+    Parser p{io_delegate};
+    if (!p.ParseFile(file))
+      return false;
+    AidlDocument* doc = p.GetDocument();
+    string line;
+
+    const AidlInterface* interface = doc->GetInterface();
+
+    if (interface != nullptr &&
+        !writer->Write("interface %s;\n",
+                       interface->GetCanonicalName().c_str())) {
+      return false;
+    }
+
+    for (const auto& parcelable : doc->GetParcelables()) {
+      if (!writer->Write("parcelable %s;\n",
+                         parcelable->GetCanonicalName().c_str())) {
+        return false;
+      }
+    }
+  }
+
+  return writer->Close();
+}
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/aidl.h b/aidl/aidl.h
new file mode 100644
index 0000000..2e5b0ee
--- /dev/null
+++ b/aidl/aidl.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_AIDL_H_
+#define AIDL_AIDL_H_
+
+#include <limits>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "aidl_language.h"
+#include "io_delegate.h"
+#include "options.h"
+#include "type_namespace.h"
+
+namespace android {
+namespace aidl {
+
+enum class AidlError {
+  UNKOWN = std::numeric_limits<int32_t>::min(),
+  BAD_PRE_PROCESSED_FILE,
+  PARSE_ERROR,
+  FOUND_PARCELABLE,
+  BAD_PACKAGE,
+  BAD_IMPORT,
+  BAD_TYPE,
+  BAD_METHOD_ID,
+  GENERATION_ERROR,
+  BAD_CONSTANTS,
+
+  OK = 0,
+};
+
+int compile_aidl_to_cpp(const CppOptions& options,
+                        const IoDelegate& io_delegate);
+int compile_aidl_to_java(const JavaOptions& options,
+                         const IoDelegate& io_delegate);
+bool preprocess_aidl(const JavaOptions& options,
+                     const IoDelegate& io_delegate);
+
+namespace internals {
+
+AidlError load_and_validate_aidl(
+    const std::vector<std::string>& preprocessed_files,
+    const std::vector<std::string>& import_paths,
+    const std::string& input_file_name,
+    const IoDelegate& io_delegate,
+    TypeNamespace* types,
+    std::unique_ptr<AidlInterface>* returned_interface,
+    std::vector<std::unique_ptr<AidlImport>>* returned_imports);
+
+bool parse_preprocessed_file(const IoDelegate& io_delegate,
+                             const std::string& filename, TypeNamespace* types);
+
+} // namespace internals
+
+}  // namespace android
+}  // namespace aidl
+
+#endif  // AIDL_AIDL_H_
diff --git a/aidl/aidl_language.cpp b/aidl/aidl_language.cpp
new file mode 100644
index 0000000..bbe305b
--- /dev/null
+++ b/aidl/aidl_language.cpp
@@ -0,0 +1,312 @@
+#include "aidl_language.h"
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include "aidl_language_y.h"
+#include "logging.h"
+
+#ifdef _WIN32
+int isatty(int  fd)
+{
+    return (fd == 0);
+}
+#endif
+
+using android::aidl::IoDelegate;
+using android::base::Join;
+using android::base::Split;
+using std::cerr;
+using std::endl;
+using std::string;
+using std::unique_ptr;
+
+void yylex_init(void **);
+void yylex_destroy(void *);
+void yyset_in(FILE *f, void *);
+int yyparse(Parser*);
+YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *);
+void yy_delete_buffer(YY_BUFFER_STATE, void *);
+
+AidlToken::AidlToken(const std::string& text, const std::string& comments)
+    : text_(text),
+      comments_(comments) {}
+
+AidlType::AidlType(const std::string& name, unsigned line,
+                   const std::string& comments, bool is_array)
+    : name_(name),
+      line_(line),
+      is_array_(is_array),
+      comments_(comments) {}
+
+string AidlType::ToString() const {
+  return name_ + (is_array_ ? "[]" : "");
+}
+
+AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type,
+                           std::string name, unsigned line)
+    : type_(type),
+      direction_(direction),
+      direction_specified_(true),
+      name_(name),
+      line_(line) {}
+
+AidlArgument::AidlArgument(AidlType* type, std::string name, unsigned line)
+    : type_(type),
+      direction_(AidlArgument::IN_DIR),
+      direction_specified_(false),
+      name_(name),
+      line_(line) {}
+
+string AidlArgument::ToString() const {
+  string ret;
+
+  if (direction_specified_) {
+    switch(direction_) {
+    case AidlArgument::IN_DIR:
+      ret += "in ";
+      break;
+    case AidlArgument::OUT_DIR:
+      ret += "out ";
+      break;
+    case AidlArgument::INOUT_DIR:
+      ret += "inout ";
+      break;
+    }
+  }
+
+  ret += type_->ToString();
+  ret += " ";
+  ret += name_;
+
+  return ret;
+}
+
+AidlIntConstant::AidlIntConstant(std::string name, int32_t value)
+    : name_(name),
+      value_(value),
+      is_valid_(true) {}
+
+AidlIntConstant::AidlIntConstant(std::string name,
+                                 std::string value,
+                                 unsigned line_number)
+    : name_(name) {
+  uint32_t unsigned_val;
+  if (!android::base::ParseUint(value.c_str(), &unsigned_val)) {
+    is_valid_ = false;
+    LOG(ERROR) << "Found invalid int value '" << value
+               << "' on line " << line_number;
+  } else {
+    // Converting from unsigned to signed integer.
+    value_ = unsigned_val;
+    is_valid_ = true;
+  }
+}
+
+AidlStringConstant::AidlStringConstant(std::string name,
+                                       std::string value,
+                                       unsigned line_number)
+    : name_(name),
+      value_(value) {
+  is_valid_ = true;
+  for (size_t i = 0; i < value_.length(); ++i) {
+    const char& c = value_[i];
+    if (c <= 0x1f || // control characters are < 0x20
+        c >= 0x7f || // DEL is 0x7f
+        c == '\\') { // Disallow backslashes for future proofing.
+      LOG(ERROR) << "Found invalid character at index " << i
+                 << " in string constant '" << value_
+                 << "' beginning on line " << line_number;
+      is_valid_ = false;
+      break;
+    }
+  }
+}
+
+AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
+                       std::vector<std::unique_ptr<AidlArgument>>* args,
+                       unsigned line, const std::string& comments, int id)
+    : oneway_(oneway),
+      comments_(comments),
+      type_(type),
+      name_(name),
+      line_(line),
+      arguments_(std::move(*args)),
+      id_(id) {
+  has_id_ = true;
+  delete args;
+  for (const unique_ptr<AidlArgument>& a : arguments_) {
+    if (a->IsIn()) { in_arguments_.push_back(a.get()); }
+    if (a->IsOut()) { out_arguments_.push_back(a.get()); }
+  }
+}
+
+AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
+                       std::vector<std::unique_ptr<AidlArgument>>* args,
+                       unsigned line, const std::string& comments)
+    : AidlMethod(oneway, type, name, args, line, comments, 0) {
+  has_id_ = false;
+}
+
+Parser::Parser(const IoDelegate& io_delegate)
+    : io_delegate_(io_delegate) {
+  yylex_init(&scanner_);
+}
+
+AidlParcelable::AidlParcelable(AidlQualifiedName* name, unsigned line,
+                               const std::vector<std::string>& package,
+                               const std::string& cpp_header)
+    : name_(name),
+      line_(line),
+      package_(package),
+      cpp_header_(cpp_header) {
+  // Strip off quotation marks if we actually have a cpp header.
+  if (cpp_header_.length() >= 2) {
+    cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2);
+  }
+}
+
+std::string AidlParcelable::GetPackage() const {
+  return Join(package_, '.');
+}
+
+std::string AidlParcelable::GetCanonicalName() const {
+  if (package_.empty()) {
+    return GetName();
+  }
+  return GetPackage() + "." + GetName();
+}
+
+AidlInterface::AidlInterface(const std::string& name, unsigned line,
+                             const std::string& comments, bool oneway,
+                             std::vector<std::unique_ptr<AidlMember>>* members,
+                             const std::vector<std::string>& package)
+    : name_(name),
+      comments_(comments),
+      line_(line),
+      oneway_(oneway),
+      package_(package) {
+  for (auto& member : *members) {
+    AidlMember* local = member.release();
+    AidlMethod* method = local->AsMethod();
+    AidlIntConstant* int_constant = local->AsIntConstant();
+    AidlStringConstant* string_constant = local->AsStringConstant();
+
+    if (method) {
+      methods_.emplace_back(method);
+    } else if (int_constant) {
+      int_constants_.emplace_back(int_constant);
+    } else if (string_constant) {
+      string_constants_.emplace_back(string_constant);
+    } else {
+      LOG(FATAL) << "Member is neither method nor constant!";
+    }
+  }
+
+  delete members;
+}
+
+std::string AidlInterface::GetPackage() const {
+  return Join(package_, '.');
+}
+
+std::string AidlInterface::GetCanonicalName() const {
+  if (package_.empty()) {
+    return GetName();
+  }
+  return GetPackage() + "." + GetName();
+}
+
+AidlDocument::AidlDocument(AidlInterface* interface)
+    : interface_(interface) {}
+
+AidlQualifiedName::AidlQualifiedName(std::string term,
+                                     std::string comments)
+    : terms_({term}),
+      comments_(comments) {
+  if (term.find('.') != string::npos) {
+    terms_ = Split(term, ".");
+    for (const auto& term: terms_) {
+      if (term.empty()) {
+        LOG(FATAL) << "Malformed qualified identifier: '" << term << "'";
+      }
+    }
+  }
+}
+
+void AidlQualifiedName::AddTerm(const std::string& term) {
+  terms_.push_back(term);
+}
+
+AidlImport::AidlImport(const std::string& from,
+                       const std::string& needed_class, unsigned line)
+    : from_(from),
+      needed_class_(needed_class),
+      line_(line) {}
+
+Parser::~Parser() {
+  if (raw_buffer_) {
+    yy_delete_buffer(buffer_, scanner_);
+    raw_buffer_.reset();
+  }
+  yylex_destroy(scanner_);
+}
+
+bool Parser::ParseFile(const string& filename) {
+  // Make sure we can read the file first, before trashing previous state.
+  unique_ptr<string> new_buffer = io_delegate_.GetFileContents(filename);
+  if (!new_buffer) {
+    LOG(ERROR) << "Error while opening file for parsing: '" << filename << "'";
+    return false;
+  }
+
+  // Throw away old parsing state if we have any.
+  if (raw_buffer_) {
+    yy_delete_buffer(buffer_, scanner_);
+    raw_buffer_.reset();
+  }
+
+  raw_buffer_ = std::move(new_buffer);
+  // We're going to scan this buffer in place, and yacc demands we put two
+  // nulls at the end.
+  raw_buffer_->append(2u, '\0');
+  filename_ = filename;
+  package_.reset();
+  error_ = 0;
+  document_.reset();
+
+  buffer_ = yy_scan_buffer(&(*raw_buffer_)[0], raw_buffer_->length(), scanner_);
+
+  if (yy::parser(this).parse() != 0 || error_ != 0) {
+    return false;}
+
+  if (document_.get() != nullptr)
+    return true;
+
+  LOG(ERROR) << "Parser succeeded but yielded no document!";
+  return false;
+}
+
+void Parser::ReportError(const string& err, unsigned line) {
+  cerr << filename_ << ":" << line << ": " << err << endl;
+  error_ = 1;
+}
+
+std::vector<std::string> Parser::Package() const {
+  if (!package_) {
+    return {};
+  }
+  return package_->GetTerms();
+}
+
+void Parser::AddImport(AidlQualifiedName* name, unsigned line) {
+  imports_.emplace_back(new AidlImport(this->FileName(),
+                                       name->GetDotName(), line));
+  delete name;
+}
diff --git a/aidl/aidl_language.h b/aidl/aidl_language.h
new file mode 100644
index 0000000..e27cd10
--- /dev/null
+++ b/aidl/aidl_language.h
@@ -0,0 +1,428 @@
+#ifndef AIDL_AIDL_LANGUAGE_H_
+#define AIDL_AIDL_LANGUAGE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+
+#include <io_delegate.h>
+
+struct yy_buffer_state;
+typedef yy_buffer_state* YY_BUFFER_STATE;
+
+class AidlToken {
+ public:
+  AidlToken(const std::string& text, const std::string& comments);
+
+  const std::string& GetText() const { return text_; }
+  const std::string& GetComments() const { return comments_; }
+
+ private:
+  std::string text_;
+  std::string comments_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlToken);
+};
+
+class AidlNode {
+ public:
+  AidlNode() = default;
+  virtual ~AidlNode() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AidlNode);
+};
+
+namespace android {
+namespace aidl {
+
+class ValidatableType;
+
+}  // namespace aidl
+}  // namespace android
+
+class AidlAnnotatable : public AidlNode {
+ public:
+  enum Annotation : uint32_t {
+    AnnotationNone = 0,
+    AnnotationNullable = 1 << 0,
+    AnnotationUtf8 = 1 << 1,
+    AnnotationUtf8InCpp = 1 << 2,
+  };
+
+  AidlAnnotatable() = default;
+  virtual ~AidlAnnotatable() = default;
+
+  void Annotate(AidlAnnotatable::Annotation annotation) {
+    annotations_ =
+        static_cast<AidlAnnotatable::Annotation>(annotations_ | annotation);
+  }
+  bool IsNullable() const {
+    return annotations_ & AnnotationNullable;
+  }
+  bool IsUtf8() const {
+    return annotations_ & AnnotationUtf8;
+  }
+  bool IsUtf8InCpp() const {
+    return annotations_ & AnnotationUtf8InCpp;
+  }
+
+ private:
+  Annotation annotations_ = AnnotationNone;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlAnnotatable);
+};
+
+class AidlType : public AidlAnnotatable {
+ public:
+  AidlType(const std::string& name, unsigned line,
+           const std::string& comments, bool is_array);
+  virtual ~AidlType() = default;
+
+  const std::string& GetName() const { return name_; }
+  unsigned GetLine() const { return line_; }
+  bool IsArray() const { return is_array_; }
+  const std::string& GetComments() const { return comments_; }
+
+  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);
+};
+
+class AidlArgument : public AidlNode {
+ public:
+  enum Direction { IN_DIR = 1, OUT_DIR = 2, INOUT_DIR = 3 };
+
+  AidlArgument(AidlArgument::Direction direction, AidlType* type,
+               std::string name, unsigned line);
+  AidlArgument(AidlType* type, std::string name, unsigned line);
+  virtual ~AidlArgument() = default;
+
+  Direction GetDirection() const { return direction_; }
+  bool IsOut() const { return direction_ & OUT_DIR; }
+  bool IsIn() const { return direction_ & IN_DIR; }
+  bool DirectionWasSpecified() const { return direction_specified_; }
+
+  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;
+
+ private:
+  std::unique_ptr<AidlType> type_;
+  Direction direction_;
+  bool direction_specified_;
+  std::string name_;
+  unsigned line_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlArgument);
+};
+
+class AidlMethod;
+class AidlIntConstant;
+class AidlStringConstant;
+class AidlMember : public AidlNode {
+ public:
+  AidlMember() = default;
+  virtual ~AidlMember() = default;
+
+  virtual AidlMethod* AsMethod() { return nullptr; }
+  virtual AidlIntConstant* AsIntConstant() { return nullptr; }
+  virtual AidlStringConstant* AsStringConstant() { return nullptr; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AidlMember);
+};
+
+class AidlIntConstant : public AidlMember {
+ public:
+  AidlIntConstant(std::string name, int32_t value);
+  AidlIntConstant(std::string name, std::string value, unsigned line_number);
+  virtual ~AidlIntConstant() = default;
+
+  const std::string& GetName() const { return name_; }
+  int GetValue() const { return value_; }
+  bool IsValid() const { return is_valid_; }
+
+  AidlIntConstant* AsIntConstant() override { return this; }
+
+ private:
+  std::string name_;
+  int32_t value_;
+  bool is_valid_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlIntConstant);
+};
+
+class AidlStringConstant : public AidlMember {
+ public:
+  AidlStringConstant(std::string name, std::string value, unsigned line_number);
+  virtual ~AidlStringConstant() = default;
+
+  const std::string& GetName() const { return name_; }
+  const std::string& GetValue() const { return value_; }
+  bool IsValid() const { return is_valid_; }
+
+  AidlStringConstant* AsStringConstant() override { return this; }
+
+ private:
+  std::string name_;
+  std::string value_;
+  bool is_valid_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlStringConstant);
+};
+
+class AidlMethod : public AidlMember {
+ public:
+  AidlMethod(bool oneway, AidlType* type, std::string name,
+             std::vector<std::unique_ptr<AidlArgument>>* args,
+             unsigned line, const std::string& comments);
+  AidlMethod(bool oneway, AidlType* type, std::string name,
+             std::vector<std::unique_ptr<AidlArgument>>* args,
+             unsigned line, const std::string& comments, int id);
+  virtual ~AidlMethod() = default;
+
+  AidlMethod* AsMethod() override { return this; }
+
+  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_; }
+  bool HasId() const { return has_id_; }
+  int GetId() { return id_; }
+  void SetId(unsigned id) { id_ = id; }
+
+  const std::vector<std::unique_ptr<AidlArgument>>& GetArguments() const {
+    return arguments_;
+  }
+  // An inout parameter will appear in both GetInArguments()
+  // and GetOutArguments().  AidlMethod retains ownership of the argument
+  // pointers returned in this way.
+  const std::vector<const AidlArgument*>& GetInArguments() const {
+    return in_arguments_;
+  }
+  const std::vector<const AidlArgument*>& GetOutArguments() const {
+    return out_arguments_;
+  }
+
+ private:
+  bool oneway_;
+  std::string comments_;
+  std::unique_ptr<AidlType> type_;
+  std::string name_;
+  unsigned line_;
+  const std::vector<std::unique_ptr<AidlArgument>> arguments_;
+  std::vector<const AidlArgument*> in_arguments_;
+  std::vector<const AidlArgument*> out_arguments_;
+  bool has_id_;
+  int id_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlMethod);
+};
+
+class AidlParcelable;
+class AidlInterface;
+class AidlDocument : public AidlNode {
+ public:
+  AidlDocument() = default;
+  explicit AidlDocument(AidlInterface* interface);
+  virtual ~AidlDocument() = default;
+
+  const AidlInterface* GetInterface() const { return interface_.get(); }
+  AidlInterface* ReleaseInterface() { return interface_.release(); }
+
+  const std::vector<std::unique_ptr<AidlParcelable>>& GetParcelables() const {
+    return parcelables_;
+  }
+
+  void AddParcelable(AidlParcelable* parcelable) {
+    parcelables_.push_back(std::unique_ptr<AidlParcelable>(parcelable));
+  }
+
+ private:
+  std::vector<std::unique_ptr<AidlParcelable>> parcelables_;
+  std::unique_ptr<AidlInterface> interface_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlDocument);
+};
+
+class AidlQualifiedName : public AidlNode {
+ public:
+  AidlQualifiedName(std::string term, std::string comments);
+  virtual ~AidlQualifiedName() = default;
+
+  const std::vector<std::string>& GetTerms() const { return terms_; }
+  const std::string& GetComments() const { return comments_; }
+  std::string GetDotName() const { return android::base::Join(terms_, '.'); }
+
+  void AddTerm(const std::string& term);
+
+ private:
+  std::vector<std::string> terms_;
+  std::string comments_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlQualifiedName);
+};
+
+class AidlParcelable : public AidlNode {
+ public:
+  AidlParcelable(AidlQualifiedName* name, unsigned line,
+                 const std::vector<std::string>& package,
+                 const std::string& cpp_header = "");
+  virtual ~AidlParcelable() = default;
+
+  std::string GetName() const { return name_->GetDotName(); }
+  unsigned GetLine() const { return line_; }
+  std::string GetPackage() const;
+  const std::vector<std::string>& GetSplitPackage() const { return package_; }
+  std::string GetCppHeader() const { return cpp_header_; }
+  std::string GetCanonicalName() const;
+
+ private:
+  std::unique_ptr<AidlQualifiedName> name_;
+  unsigned line_;
+  const std::vector<std::string> package_;
+  std::string cpp_header_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlParcelable);
+};
+
+class AidlInterface : public AidlAnnotatable {
+ public:
+  AidlInterface(const std::string& name, unsigned line,
+                const std::string& comments, bool oneway_,
+                std::vector<std::unique_ptr<AidlMember>>* members,
+                const std::vector<std::string>& package);
+  virtual ~AidlInterface() = default;
+
+  const std::string& GetName() const { return name_; }
+  unsigned GetLine() const { return line_; }
+  const std::string& GetComments() const { return comments_; }
+  bool IsOneway() const { return oneway_; }
+  const std::vector<std::unique_ptr<AidlMethod>>& GetMethods() const
+      { return methods_; }
+  const std::vector<std::unique_ptr<AidlIntConstant>>& GetIntConstants() const
+      { return int_constants_; }
+  const std::vector<std::unique_ptr<AidlStringConstant>>&
+      GetStringConstants() const { return string_constants_; }
+  std::string GetPackage() const;
+  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_;
+  unsigned line_;
+  bool oneway_;
+  std::vector<std::unique_ptr<AidlMethod>> methods_;
+  std::vector<std::unique_ptr<AidlIntConstant>> int_constants_;
+  std::vector<std::unique_ptr<AidlStringConstant>> string_constants_;
+  std::vector<std::string> package_;
+
+  const android::aidl::ValidatableType* language_type_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlInterface);
+};
+
+class AidlImport : public AidlNode {
+ public:
+  AidlImport(const std::string& from, const std::string& needed_class,
+             unsigned line);
+  virtual ~AidlImport() = default;
+
+  const std::string& GetFileFrom() const { return from_; }
+  const std::string& GetFilename() const { return filename_; }
+  const std::string& GetNeededClass() const { return needed_class_; }
+  unsigned GetLine() const { return line_; }
+
+  void SetFilename(const std::string& filename) { filename_ = filename; }
+
+ private:
+  std::string from_;
+  std::string filename_;
+  std::string needed_class_;
+  unsigned line_;
+
+  DISALLOW_COPY_AND_ASSIGN(AidlImport);
+};
+
+class Parser {
+ public:
+  explicit Parser(const android::aidl::IoDelegate& io_delegate);
+  ~Parser();
+
+  // Parse contents of file |filename|.
+  bool ParseFile(const std::string& filename);
+
+  void ReportError(const std::string& err, unsigned line);
+
+  bool FoundNoErrors() const { return error_ == 0; }
+  const std::string& FileName() const { return filename_; }
+  void* Scanner() const { return scanner_; }
+
+  void SetDocument(AidlDocument* doc) { document_.reset(doc); };
+
+  void AddImport(AidlQualifiedName* name, unsigned line);
+
+  std::vector<std::string> Package() const;
+  void SetPackage(AidlQualifiedName* name) { package_.reset(name); }
+
+  AidlDocument* GetDocument() const { return document_.get(); }
+  AidlDocument* ReleaseDocument() { return document_.release(); }
+  const std::vector<std::unique_ptr<AidlImport>>& GetImports() {
+    return imports_;
+  }
+
+  void ReleaseImports(std::vector<std::unique_ptr<AidlImport>>* ret) {
+      *ret = std::move(imports_);
+      imports_.clear();
+  }
+
+ private:
+  const android::aidl::IoDelegate& io_delegate_;
+  int error_ = 0;
+  std::string filename_;
+  std::unique_ptr<AidlQualifiedName> package_;
+  void* scanner_ = nullptr;
+  std::unique_ptr<AidlDocument> document_;
+  std::vector<std::unique_ptr<AidlImport>> imports_;
+  std::unique_ptr<std::string> raw_buffer_;
+  YY_BUFFER_STATE buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(Parser);
+};
+
+#endif // AIDL_AIDL_LANGUAGE_H_
diff --git a/aidl/aidl_language_l.ll b/aidl/aidl_language_l.ll
new file mode 100644
index 0000000..a56758b
--- /dev/null
+++ b/aidl/aidl_language_l.ll
@@ -0,0 +1,106 @@
+%{
+#include <string.h>
+#include <stdlib.h>
+
+#include "aidl_language.h"
+#include "aidl_language_y.h"
+
+#define YY_USER_ACTION yylloc->columns(yyleng);
+%}
+
+%option yylineno
+%option noyywrap
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+%x COPYING LONG_COMMENT
+
+identifier  [_a-zA-Z][_a-zA-Z0-9]*
+whitespace  ([ \t\r]+)
+intvalue    [-+]?(0|[1-9][0-9]*)
+hexvalue    0[x|X][0-9a-fA-F]+
+
+%%
+%{
+  /* This happens at every call to yylex (every time we receive one token) */
+  std::string extra_text;
+  yylloc->step();
+%}
+
+
+\%\%\{                { extra_text += "/**"; BEGIN(COPYING); }
+<COPYING>\}\%\%       { extra_text += "**/"; yylloc->step(); BEGIN(INITIAL); }
+<COPYING>.*           { extra_text += yytext; }
+<COPYING>\n+          { extra_text += yytext; yylloc->lines(yyleng); }
+
+\/\*                  { extra_text += yytext; BEGIN(LONG_COMMENT); }
+<LONG_COMMENT>\*+\/   { extra_text += yytext; yylloc->step(); BEGIN(INITIAL);  }
+<LONG_COMMENT>\*+     { extra_text += yytext; }
+<LONG_COMMENT>\n+     { extra_text += yytext; yylloc->lines(yyleng); }
+<LONG_COMMENT>[^*\n]+ { extra_text += yytext; }
+
+\"[^\"]*\"            { yylval->token = new AidlToken(yytext, extra_text);
+                        return yy::parser::token::C_STR; }
+
+\/\/.*\n              { extra_text += yytext; yylloc->lines(1); yylloc->step(); }
+
+\n+                   { yylloc->lines(yyleng); yylloc->step(); }
+{whitespace}          {}
+<<EOF>>               { yyterminate(); }
+
+    /* symbols */
+;                     { return ';'; }
+\{                    { return '{'; }
+\}                    { return '}'; }
+=                     { return '='; }
+,                     { return ','; }
+\.                    { return '.'; }
+\(                    { return '('; }
+\)                    { return ')'; }
+\[                    { return '['; }
+\]                    { return ']'; }
+\<                    { return '<'; }
+\>                    { return '>'; }
+
+    /* keywords */
+parcelable            { return yy::parser::token::PARCELABLE; }
+import                { return yy::parser::token::IMPORT; }
+package               { return yy::parser::token::PACKAGE; }
+int                   { return yy::parser::token::INT; }
+String                { return yy::parser::token::STRING; }
+in                    { return yy::parser::token::IN; }
+out                   { return yy::parser::token::OUT; }
+inout                 { return yy::parser::token::INOUT; }
+cpp_header            { return yy::parser::token::CPP_HEADER; }
+const                 { return yy::parser::token::CONST; }
+@nullable             { return yy::parser::token::ANNOTATION_NULLABLE; }
+@utf8                 { return yy::parser::token::ANNOTATION_UTF8; }
+@utf8InCpp            { return yy::parser::token::ANNOTATION_UTF8_CPP; }
+
+interface             { yylval->token = new AidlToken("interface", extra_text);
+                        return yy::parser::token::INTERFACE;
+                      }
+oneway                { yylval->token = new AidlToken("oneway", extra_text);
+                        return yy::parser::token::ONEWAY;
+                      }
+
+    /* scalars */
+{identifier}          { yylval->token = new AidlToken(yytext, extra_text);
+                        return yy::parser::token::IDENTIFIER;
+                      }
+{intvalue}            { yylval->integer = std::stoi(yytext);
+                        return yy::parser::token::INTVALUE; }
+{hexvalue}            { yylval->token = new AidlToken(yytext, extra_text);
+                        return yy::parser::token::HEXVALUE; }
+
+    /* syntax error! */
+.                     { printf("UNKNOWN(%s)", yytext);
+                        yylval->token = new AidlToken(yytext, extra_text);
+                        return yy::parser::token::IDENTIFIER;
+                      }
+
+%%
+
+// comment and whitespace handling
+// ================================================
diff --git a/aidl/aidl_language_y.yy b/aidl/aidl_language_y.yy
new file mode 100644
index 0000000..4ad6754
--- /dev/null
+++ b/aidl/aidl_language_y.yy
@@ -0,0 +1,321 @@
+%{
+#include "aidl_language.h"
+#include "aidl_language_y.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int yylex(yy::parser::semantic_type *, yy::parser::location_type *, void *);
+
+#define lex_scanner ps->Scanner()
+
+%}
+
+%parse-param { Parser* ps }
+%lex-param { void *lex_scanner }
+
+%pure-parser
+%skeleton "glr.cc"
+
+%union {
+    AidlToken* token;
+    int integer;
+    std::string *str;
+    AidlType::Annotation annotation;
+    AidlType::Annotation annotation_list;
+    AidlType* type;
+    AidlType* unannotated_type;
+    AidlArgument* arg;
+    AidlArgument::Direction direction;
+    std::vector<std::unique_ptr<AidlArgument>>* arg_list;
+    AidlMethod* method;
+    AidlMember* constant;
+    std::vector<std::unique_ptr<AidlMember>>* members;
+    AidlQualifiedName* qname;
+    AidlInterface* interface_obj;
+    AidlParcelable* parcelable;
+    AidlDocument* parcelable_list;
+}
+
+%token<token> IDENTIFIER INTERFACE ONEWAY C_STR HEXVALUE
+%token<integer> INTVALUE
+
+%token '(' ')' ',' '=' '[' ']' '<' '>' '.' '{' '}' ';'
+%token IN OUT INOUT PACKAGE IMPORT PARCELABLE CPP_HEADER CONST INT STRING
+%token ANNOTATION_NULLABLE ANNOTATION_UTF8 ANNOTATION_UTF8_CPP
+
+%type<parcelable_list> parcelable_decls
+%type<parcelable> parcelable_decl
+%type<members> members
+%type<interface_obj> interface_decl
+%type<method> method_decl
+%type<constant> constant_decl
+%type<annotation> annotation
+%type<annotation_list>annotation_list
+%type<type> type
+%type<unannotated_type> unannotated_type
+%type<arg_list> arg_list
+%type<arg> arg
+%type<direction> direction
+%type<str> generic_list
+%type<qname> qualified_name
+
+%type<token> identifier error
+%%
+document
+ : package imports parcelable_decls
+  { ps->SetDocument($3); }
+ | package imports interface_decl
+  { ps->SetDocument(new AidlDocument($3)); };
+
+/* A couple of tokens that are keywords elsewhere are identifiers when
+ * occurring in the identifier position. Therefore identifier is a
+ * non-terminal, which is either an IDENTIFIER token, or one of the
+ * aforementioned keyword tokens.
+ */
+identifier
+ : IDENTIFIER
+  { $$ = $1; }
+ | CPP_HEADER
+  { $$ = new AidlToken("cpp_header", ""); }
+ | INT
+  { $$ = new AidlToken("int", ""); }
+ | STRING
+  { $$ = new AidlToken("String", ""); }
+ ;
+
+package
+ : {}
+ | PACKAGE qualified_name ';'
+  { ps->SetPackage($2); };
+
+imports
+ : {}
+ | import imports {};
+
+import
+ : IMPORT qualified_name ';'
+  { ps->AddImport($2, @1.begin.line); };
+
+qualified_name
+ : identifier {
+    $$ = new AidlQualifiedName($1->GetText(), $1->GetComments());
+    delete $1;
+  }
+ | qualified_name '.' identifier
+  { $$ = $1;
+    $$->AddTerm($3->GetText());
+  };
+
+parcelable_decls
+ :
+  { $$ = new AidlDocument(); }
+ | parcelable_decls parcelable_decl {
+   $$ = $1;
+   $$->AddParcelable($2);
+  }
+ | parcelable_decls error {
+    fprintf(stderr, "%s:%d: syntax error don't know what to do with \"%s\"\n",
+            ps->FileName().c_str(),
+            @2.begin.line, $2->GetText().c_str());
+    $$ = $1;
+  };
+
+parcelable_decl
+ : PARCELABLE qualified_name ';' {
+    $$ = new AidlParcelable($2, @2.begin.line, ps->Package());
+  }
+ | PARCELABLE qualified_name CPP_HEADER C_STR ';' {
+    $$ = new AidlParcelable($2, @2.begin.line, ps->Package(), $4->GetText());
+  }
+ | PARCELABLE ';' {
+    fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
+            ps->FileName().c_str(), @1.begin.line);
+    $$ = NULL;
+  }
+ | PARCELABLE error ';' {
+    fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
+            ps->FileName().c_str(), @2.begin.line, $2->GetText().c_str());
+    $$ = NULL;
+  };
+
+interface_decl
+ : annotation_list INTERFACE identifier '{' members '}' {
+    $$ = new AidlInterface($3->GetText(), @2.begin.line, $2->GetComments(),
+                           false, $5, ps->Package());
+    $$->Annotate($1);
+    delete $2;
+    delete $3;
+  }
+ | annotation_list ONEWAY INTERFACE identifier '{' members '}' {
+    $$ = new AidlInterface($4->GetText(), @4.begin.line, $2->GetComments(),
+                           true, $6, ps->Package());
+    $$->Annotate($1);
+    delete $2;
+    delete $3;
+    delete $4;
+  }
+ | annotation_list INTERFACE error '{' members '}' {
+    fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected "
+                    "type name, saw \"%s\"\n",
+            ps->FileName().c_str(), @3.begin.line, $3->GetText().c_str());
+    $$ = NULL;
+    delete $2;
+    delete $3;
+    delete $5;
+  }
+ | annotation_list INTERFACE error '}' {
+    fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected "
+                    "type name, saw \"%s\"\n",
+            ps->FileName().c_str(), @3.begin.line, $3->GetText().c_str());
+    $$ = NULL;
+    delete $2;
+    delete $3;
+  };
+
+members
+ :
+  { $$ = new std::vector<std::unique_ptr<AidlMember>>(); }
+ | members method_decl
+  { $1->push_back(std::unique_ptr<AidlMember>($2)); }
+ | members constant_decl
+  { $1->push_back(std::unique_ptr<AidlMember>($2)); }
+ | members error ';' {
+    fprintf(stderr, "%s:%d: syntax error before ';' "
+                    "(expected method or constant declaration)\n",
+            ps->FileName().c_str(), @3.begin.line);
+    $$ = $1;
+  };
+
+constant_decl
+ : CONST INT identifier '=' INTVALUE ';' {
+    $$ = new AidlIntConstant($3->GetText(), $5);
+    delete $3;
+   }
+ | CONST INT identifier '=' HEXVALUE ';' {
+    $$ = new AidlIntConstant($3->GetText(), $5->GetText(), @5.begin.line);
+    delete $3;
+   }
+ | CONST STRING identifier '=' C_STR ';' {
+    $$ = new AidlStringConstant($3->GetText(), $5->GetText(), @5.begin.line);
+    delete $3;
+    delete $5;
+   }
+ ;
+
+method_decl
+ : type identifier '(' arg_list ')' ';' {
+    $$ = new AidlMethod(false, $1, $2->GetText(), $4, @2.begin.line,
+                        $1->GetComments());
+    delete $2;
+  }
+ | ONEWAY type identifier '(' arg_list ')' ';' {
+    $$ = new AidlMethod(true, $2, $3->GetText(), $5, @3.begin.line,
+                        $1->GetComments());
+    delete $1;
+    delete $3;
+  }
+ | type identifier '(' arg_list ')' '=' INTVALUE ';' {
+    $$ = new AidlMethod(false, $1, $2->GetText(), $4, @2.begin.line,
+                        $1->GetComments(), $7);
+    delete $2;
+  }
+ | ONEWAY type identifier '(' arg_list ')' '=' INTVALUE ';' {
+    $$ = new AidlMethod(true, $2, $3->GetText(), $5, @3.begin.line,
+                        $1->GetComments(), $8);
+    delete $1;
+    delete $3;
+  };
+
+arg_list
+ :
+  { $$ = new std::vector<std::unique_ptr<AidlArgument>>(); }
+ | arg {
+    $$ = new std::vector<std::unique_ptr<AidlArgument>>();
+    $$->push_back(std::unique_ptr<AidlArgument>($1));
+  }
+ | arg_list ',' arg {
+    $$ = $1;
+    $$->push_back(std::unique_ptr<AidlArgument>($3));
+  }
+ | error {
+    fprintf(stderr, "%s:%d: syntax error in parameter list\n",
+            ps->FileName().c_str(), @1.begin.line);
+    $$ = new std::vector<std::unique_ptr<AidlArgument>>();
+  };
+
+arg
+ : direction type identifier {
+    $$ = new AidlArgument($1, $2, $3->GetText(), @3.begin.line);
+    delete $3;
+  };
+ | type identifier {
+    $$ = new AidlArgument($1, $2->GetText(), @2.begin.line);
+    delete $2;
+  };
+
+unannotated_type
+ : qualified_name {
+    $$ = new AidlType($1->GetDotName(), @1.begin.line, $1->GetComments(), false);
+    delete $1;
+  }
+ | qualified_name '[' ']' {
+    $$ = new AidlType($1->GetDotName(), @1.begin.line, $1->GetComments(),
+                      true);
+    delete $1;
+  }
+ | qualified_name '<' generic_list '>' {
+    $$ = new AidlType($1->GetDotName() + "<" + *$3 + ">", @1.begin.line,
+                      $1->GetComments(), false);
+    delete $1;
+    delete $3;
+  };
+
+type
+ : annotation_list unannotated_type {
+    $$ = $2;
+    $2->Annotate($1);
+  };
+
+generic_list
+ : qualified_name {
+    $$ = new std::string($1->GetDotName());
+    delete $1;
+  }
+ | generic_list ',' qualified_name {
+    $$ = new std::string(*$1 + "," + $3->GetDotName());
+    delete $1;
+    delete $3;
+  };
+
+annotation_list
+ :
+  { $$ = AidlType::AnnotationNone; }
+ | annotation_list annotation
+  { $$ = static_cast<AidlType::Annotation>($1 | $2); };
+
+annotation
+ : ANNOTATION_NULLABLE
+  { $$ = AidlType::AnnotationNullable; }
+ | ANNOTATION_UTF8
+  { $$ = AidlType::AnnotationUtf8; }
+ | ANNOTATION_UTF8_CPP
+  { $$ = AidlType::AnnotationUtf8InCpp; };
+
+direction
+ : IN
+  { $$ = AidlArgument::IN_DIR; }
+ | OUT
+  { $$ = AidlArgument::OUT_DIR; }
+ | INOUT
+  { $$ = AidlArgument::INOUT_DIR; };
+
+%%
+
+#include <ctype.h>
+#include <stdio.h>
+
+void yy::parser::error(const yy::parser::location_type& l,
+                       const std::string& errstr) {
+  ps->ReportError(errstr, l.begin.line);
+}
diff --git a/aidl/aidl_unittest.cpp b/aidl/aidl_unittest.cpp
new file mode 100644
index 0000000..0d2ba53
--- /dev/null
+++ b/aidl/aidl_unittest.cpp
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "aidl.h"
+#include "aidl_language.h"
+#include "tests/fake_io_delegate.h"
+#include "type_cpp.h"
+#include "type_java.h"
+#include "type_namespace.h"
+
+using android::aidl::test::FakeIoDelegate;
+using android::base::StringPrintf;
+using std::set;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+using android::aidl::internals::parse_preprocessed_file;
+
+namespace android {
+namespace aidl {
+namespace {
+
+const char kExpectedDepFileContents[] =
+R"(place/for/output/p/IFoo.java : \
+  p/IFoo.aidl
+
+p/IFoo.aidl :
+)";
+
+const char kExpectedParcelableDepFileContents[] =
+R"( : \
+  p/Foo.aidl
+
+p/Foo.aidl :
+)";
+
+}  // namespace
+
+class AidlTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    java_types_.Init();
+    cpp_types_.Init();
+  }
+
+  unique_ptr<AidlInterface> Parse(const string& path,
+                                  const string& contents,
+                                  TypeNamespace* types,
+                                  AidlError* error = nullptr) {
+    io_delegate_.SetFileContents(path, contents);
+    unique_ptr<AidlInterface> ret;
+    std::vector<std::unique_ptr<AidlImport>> imports;
+    AidlError actual_error = ::android::aidl::internals::load_and_validate_aidl(
+        preprocessed_files_,
+        import_paths_,
+        path,
+        io_delegate_,
+        types,
+        &ret,
+        &imports);
+    if (error != nullptr) {
+      *error = actual_error;
+    }
+    return ret;
+  }
+
+  FakeIoDelegate io_delegate_;
+  vector<string> preprocessed_files_;
+  vector<string> import_paths_;
+  java::JavaTypeNamespace java_types_;
+  cpp::TypeNamespace cpp_types_;
+};
+
+TEST_F(AidlTest, JavaAcceptsMissingPackage) {
+  EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_));
+}
+
+TEST_F(AidlTest, RejectsArraysOfBinders) {
+  import_paths_.push_back("");
+  io_delegate_.SetFileContents("bar/IBar.aidl",
+                               "package bar; interface IBar {}");
+  string path = "foo/IFoo.aidl";
+  string contents = "package foo;\n"
+                    "import bar.IBar;\n"
+                    "interface IFoo { void f(in IBar[] input); }";
+  EXPECT_EQ(nullptr, Parse(path, contents, &java_types_));
+  EXPECT_EQ(nullptr, Parse(path, contents, &cpp_types_));
+}
+
+TEST_F(AidlTest, CppRejectsMissingPackage) {
+  EXPECT_EQ(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &cpp_types_));
+  EXPECT_NE(nullptr,
+            Parse("a/IFoo.aidl", "package a; interface IFoo { }", &cpp_types_));
+}
+
+TEST_F(AidlTest, RejectsOnewayOutParameters) {
+  string oneway_interface =
+      "package a; oneway interface IFoo { void f(out int bar); }";
+  string oneway_method =
+      "package a; interface IBar { oneway void f(out int bar); }";
+  EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &cpp_types_));
+  EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &java_types_));
+  EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &cpp_types_));
+  EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &java_types_));
+}
+
+TEST_F(AidlTest, RejectsOnewayNonVoidReturn) {
+  string oneway_method = "package a; interface IFoo { oneway int f(); }";
+  EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
+  EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
+}
+
+TEST_F(AidlTest, RejectsNullablePrimitive) {
+  string oneway_method = "package a; interface IFoo { @nullable int f(); }";
+  EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
+  EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
+}
+
+TEST_F(AidlTest, ParsesNullableAnnotation) {
+  for (auto is_nullable: {true, false}) {
+    auto parse_result = Parse(
+        "a/IFoo.aidl",
+        StringPrintf( "package a; interface IFoo {%s String f(); }",
+                     (is_nullable) ? "@nullable" : ""),
+        &cpp_types_);
+    ASSERT_NE(nullptr, parse_result);
+    ASSERT_FALSE(parse_result->GetMethods().empty());
+    EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsNullable(),
+              is_nullable);
+  }
+}
+
+TEST_F(AidlTest, ParsesUtf8Annotations) {
+  for (auto is_utf8: {true, false}) {
+    auto parse_result = Parse(
+        "a/IFoo.aidl",
+        StringPrintf( "package a; interface IFoo {%s String f(); }",
+                     (is_utf8) ? "@utf8InCpp" : ""),
+        &cpp_types_);
+    ASSERT_NE(nullptr, parse_result);
+    ASSERT_FALSE(parse_result->GetMethods().empty());
+    EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsUtf8InCpp(),
+              is_utf8);
+  }
+}
+
+TEST_F(AidlTest, AcceptsOneway) {
+  string oneway_method = "package a; interface IFoo { oneway void f(int a); }";
+  string oneway_interface =
+      "package a; oneway interface IBar { void f(int a); }";
+  EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_));
+  EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_));
+  EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &cpp_types_));
+  EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &java_types_));
+}
+
+TEST_F(AidlTest, ParsesPreprocessedFile) {
+  string simple_content = "parcelable a.Foo;\ninterface b.IBar;";
+  io_delegate_.SetFileContents("path", simple_content);
+  EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo"));
+  EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_));
+  EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo"));
+  EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar"));
+}
+
+TEST_F(AidlTest, ParsesPreprocessedFileWithWhitespace) {
+  string simple_content = "parcelable    a.Foo;\n  interface b.IBar  ;\t";
+  io_delegate_.SetFileContents("path", simple_content);
+  EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo"));
+  EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_));
+  EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo"));
+  EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar"));
+}
+
+TEST_F(AidlTest, PreferImportToPreprocessed) {
+  io_delegate_.SetFileContents("preprocessed", "interface another.IBar;");
+  io_delegate_.SetFileContents("one/IBar.aidl", "package one; "
+                                                "interface IBar {}");
+  preprocessed_files_.push_back("preprocessed");
+  import_paths_.push_back("");
+  auto parse_result = Parse(
+      "p/IFoo.aidl", "package p; import one.IBar; interface IFoo {}",
+      &java_types_);
+  EXPECT_NE(nullptr, parse_result);
+  // We expect to know about both kinds of IBar
+  EXPECT_TRUE(java_types_.HasTypeByCanonicalName("one.IBar"));
+  EXPECT_TRUE(java_types_.HasTypeByCanonicalName("another.IBar"));
+  // But if we request just "IBar" we should get our imported one.
+  AidlType ambiguous_type("IBar", 0, "", false /* not an array */);
+  const java::Type* type = java_types_.Find(ambiguous_type);
+  ASSERT_TRUE(type);
+  EXPECT_EQ("one.IBar", type->CanonicalName());
+}
+
+TEST_F(AidlTest, WritePreprocessedFile) {
+  io_delegate_.SetFileContents("p/Outer.aidl",
+                               "package p; parcelable Outer.Inner;");
+  io_delegate_.SetFileContents("one/IBar.aidl", "package one; import p.Outer;"
+                                                "interface IBar {}");
+
+  JavaOptions options;
+  options.output_file_name_ = "preprocessed";
+  options.files_to_preprocess_.resize(2);
+  options.files_to_preprocess_[0] = "p/Outer.aidl";
+  options.files_to_preprocess_[1] = "one/IBar.aidl";
+  EXPECT_TRUE(::android::aidl::preprocess_aidl(options, io_delegate_));
+
+  string output;
+  EXPECT_TRUE(io_delegate_.GetWrittenContents("preprocessed", &output));
+  EXPECT_EQ("parcelable p.Outer.Inner;\ninterface one.IBar;\n", output);
+}
+
+TEST_F(AidlTest, RequireOuterClass) {
+  io_delegate_.SetFileContents("p/Outer.aidl",
+                               "package p; parcelable Outer.Inner;");
+  import_paths_.push_back("");
+  auto parse_result = Parse(
+      "p/IFoo.aidl",
+      "package p; import p.Outer; interface IFoo { void f(in Inner c); }",
+      &java_types_);
+  EXPECT_EQ(nullptr, parse_result);
+}
+
+TEST_F(AidlTest, ParseCompoundParcelableFromPreprocess) {
+  io_delegate_.SetFileContents("preprocessed",
+                               "parcelable p.Outer.Inner;");
+  preprocessed_files_.push_back("preprocessed");
+  auto parse_result = Parse(
+      "p/IFoo.aidl",
+      "package p; interface IFoo { void f(in Inner c); }",
+      &java_types_);
+  // TODO(wiley): This should actually return nullptr because we require
+  //              the outer class name.  However, for legacy reasons,
+  //              this behavior must be maintained.  b/17415692
+  EXPECT_NE(nullptr, parse_result);
+}
+
+TEST_F(AidlTest, FailOnParcelable) {
+  JavaOptions options;
+  options.input_file_name_ = "p/IFoo.aidl";
+  io_delegate_.SetFileContents(options.input_file_name_,
+                               "package p; parcelable IFoo;");
+  // By default, we shouldn't fail on parcelable.
+  EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
+  options.fail_on_parcelable_ = true;
+  EXPECT_NE(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
+}
+
+TEST_F(AidlTest, FailOnDuplicateConstantNames) {
+  AidlError reported_error;
+  EXPECT_EQ(nullptr,
+            Parse("p/IFoo.aidl",
+                   R"(package p;
+                      interface IFoo {
+                        const String DUPLICATED = "d";
+                        const int DUPLICATED = 1;
+                      }
+                   )",
+                   &cpp_types_,
+                   &reported_error));
+  EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error);
+}
+
+TEST_F(AidlTest, FailOnMalformedConstHexValue) {
+  AidlError reported_error;
+  EXPECT_EQ(nullptr,
+            Parse("p/IFoo.aidl",
+                   R"(package p;
+                      interface IFoo {
+                        const int BAD_HEX_VALUE = 0xffffffffffffffffff;
+                      }
+                   )",
+                   &cpp_types_,
+                   &reported_error));
+  EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error);
+}
+
+TEST_F(AidlTest, ParsePositiveConstHexValue) {
+  AidlError reported_error;
+  auto cpp_parse_result =
+    Parse("p/IFoo.aidl",
+           R"(package p;
+              interface IFoo {
+                const int POSITIVE_HEX_VALUE = 0xf5;
+              }
+           )",
+           &cpp_types_,
+           &reported_error);
+  EXPECT_NE(nullptr, cpp_parse_result);
+  const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
+  EXPECT_EQ((size_t)1, cpp_int_constants.size());
+  EXPECT_EQ("POSITIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
+  EXPECT_EQ(245, cpp_int_constants[0]->GetValue());
+}
+
+TEST_F(AidlTest, ParseNegativeConstHexValue) {
+  AidlError reported_error;
+  auto cpp_parse_result =
+    Parse("p/IFoo.aidl",
+           R"(package p;
+              interface IFoo {
+                const int NEGATIVE_HEX_VALUE = 0xffffffff;
+              }
+           )",
+           &cpp_types_,
+           &reported_error);
+  EXPECT_NE(nullptr, cpp_parse_result);
+  const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
+  EXPECT_EQ((size_t)1, cpp_int_constants.size());
+  EXPECT_EQ("NEGATIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
+  EXPECT_EQ(-1, cpp_int_constants[0]->GetValue());
+}
+
+TEST_F(AidlTest, UnderstandsNativeParcelables) {
+  io_delegate_.SetFileContents(
+      "p/Bar.aidl",
+      "package p; parcelable Bar cpp_header \"baz/header\";");
+  import_paths_.push_back("");
+  const string input_path = "p/IFoo.aidl";
+  const string input = "package p; import p.Bar; interface IFoo { }";
+
+  // C++ understands C++ specific stuff
+  auto cpp_parse_result = Parse(input_path, input, &cpp_types_);
+  EXPECT_NE(nullptr, cpp_parse_result);
+  auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Bar");
+  ASSERT_NE(nullptr, cpp_type);
+  EXPECT_EQ("::p::Bar", cpp_type->CppType());
+  set<string> headers;
+  cpp_type->GetHeaders(&headers);
+  EXPECT_EQ(1u, headers.size());
+  EXPECT_EQ(1u, headers.count("baz/header"));
+
+  // Java ignores C++ specific stuff
+  auto java_parse_result = Parse(input_path, input, &java_types_);
+  EXPECT_NE(nullptr, java_parse_result);
+  auto java_type = java_types_.FindTypeByCanonicalName("p.Bar");
+  ASSERT_NE(nullptr, java_type);
+  EXPECT_EQ("p.Bar", java_type->InstantiableName());
+}
+
+TEST_F(AidlTest, WritesCorrectDependencyFile) {
+  // While the in tree build system always gives us an output file name,
+  // other android tools take advantage of our ability to infer the intended
+  // file name.  This test makes sure we handle this correctly.
+  JavaOptions options;
+  options.input_file_name_ = "p/IFoo.aidl";
+  options.output_base_folder_ = "place/for/output";
+  options.dep_file_name_ = "dep/file/path";
+  io_delegate_.SetFileContents(options.input_file_name_,
+                               "package p; interface IFoo {}");
+  EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
+  string actual_dep_file_contents;
+  EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
+                                              &actual_dep_file_contents));
+  EXPECT_EQ(actual_dep_file_contents, kExpectedDepFileContents);
+}
+
+TEST_F(AidlTest, WritesTrivialDependencyFileForParcelable) {
+  // The SDK uses aidl to decide whether a .aidl file is a parcelable.  It does
+  // this by calling aidl with every .aidl file it finds, then parsing the
+  // generated dependency files.  Those that reference .java output files are
+  // for interfaces and those that do not are parcelables.  However, for both
+  // parcelables and interfaces, we *must* generate a non-empty dependency file.
+  JavaOptions options;
+  options.input_file_name_ = "p/Foo.aidl";
+  options.output_base_folder_ = "place/for/output";
+  options.dep_file_name_ = "dep/file/path";
+  io_delegate_.SetFileContents(options.input_file_name_,
+                               "package p; parcelable Foo;");
+  EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_));
+  string actual_dep_file_contents;
+  EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_,
+                                              &actual_dep_file_contents));
+  EXPECT_EQ(actual_dep_file_contents, kExpectedParcelableDepFileContents);
+}
+
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/ast_cpp.cpp b/aidl/ast_cpp.cpp
new file mode 100644
index 0000000..783b0f3
--- /dev/null
+++ b/aidl/ast_cpp.cpp
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ast_cpp.h"
+
+#include <algorithm>
+
+#include "code_writer.h"
+#include "logging.h"
+
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace cpp {
+
+ClassDecl::ClassDecl(const std::string& name, const std::string& parent)
+    : name_(name),
+      parent_(parent) {}
+
+ClassDecl::ClassDecl(const std::string& name, const std::string& parent,
+                     std::vector<unique_ptr<Declaration>> public_members,
+                     std::vector<unique_ptr<Declaration>> private_members)
+    : name_(name),
+      parent_(parent),
+      public_members_(std::move(public_members)),
+      private_members_(std::move(private_members)) {}
+
+void ClassDecl::Write(CodeWriter* to) const {
+  to->Write("class %s ", name_.c_str());
+
+  if (parent_.length() > 0)
+      to->Write(": public %s ", parent_.c_str());
+
+  to->Write("{\n");
+
+  if (!public_members_.empty())
+      to->Write("public:\n");
+
+  for (const auto& dec : public_members_)
+    dec->Write(to);
+
+  if (!private_members_.empty())
+      to->Write("private:\n");
+
+  for (const auto& dec : private_members_)
+    dec->Write(to);
+
+  to->Write("};  // class %s\n", name_.c_str());
+}
+
+void ClassDecl::AddPublic(std::unique_ptr<Declaration> member) {
+  public_members_.push_back(std::move(member));
+}
+
+void ClassDecl::AddPrivate(std::unique_ptr<Declaration> member) {
+  private_members_.push_back(std::move(member));
+}
+
+Enum::EnumField::EnumField(const string& k, const string& v)
+    : key(k),
+      value(v) {}
+
+Enum::Enum(const string& name, const string& base_type)
+    : enum_name_(name), underlying_type_(base_type) {}
+
+Enum::Enum(const string& name) : Enum(name, "") {}
+
+void Enum::Write(CodeWriter* to) const {
+  if (underlying_type_.empty()) {
+    to->Write("enum %s {\n", enum_name_.c_str());
+  } else {
+    to->Write("enum %s : %s {\n", enum_name_.c_str(), underlying_type_.c_str());
+  }
+  for (const auto& field : fields_) {
+    if (field.value.empty()) {
+      to->Write("  %s,\n", field.key.c_str());
+    } else {
+      to->Write("  %s = %s,\n", field.key.c_str(), field.value.c_str());
+    }
+  }
+  to->Write("};\n");
+}
+
+void Enum::AddValue(const string& key, const string& value) {
+  fields_.emplace_back(key, value);
+}
+
+ArgList::ArgList(const std::string& single_argument)
+    : ArgList(vector<string>{single_argument}) {}
+
+ArgList::ArgList(const std::vector<std::string>& arg_list) {
+  for (const auto& s : arg_list) {
+    arguments_.emplace_back(new LiteralExpression(s));
+  }
+}
+
+ArgList::ArgList(std::vector<std::unique_ptr<AstNode>> arg_list)
+    : arguments_(std::move(arg_list)) {}
+
+ArgList::ArgList(ArgList&& arg_list)
+    : arguments_(std::move(arg_list.arguments_)) {}
+
+void ArgList::Write(CodeWriter* to) const {
+  to->Write("(");
+  bool is_first = true;
+  for (const auto& s : arguments_) {
+    if (!is_first) { to->Write(", "); }
+    is_first = false;
+    s->Write(to);
+  }
+  to->Write(")");
+}
+
+ConstructorDecl::ConstructorDecl(
+    const std::string& name,
+    ArgList&& arg_list)
+    : ConstructorDecl(name, std::move(arg_list), 0u) {}
+
+ConstructorDecl::ConstructorDecl(
+    const std::string& name,
+    ArgList&& arg_list,
+    uint32_t modifiers)
+    : name_(name),
+      arguments_(std::move(arg_list)),
+      modifiers_(modifiers) {}
+
+void ConstructorDecl::Write(CodeWriter* to) const {
+  if (modifiers_ & Modifiers::IS_VIRTUAL)
+    to->Write("virtual ");
+
+  if (modifiers_ & Modifiers::IS_EXPLICIT)
+    to->Write("explicit ");
+
+  to->Write("%s", name_.c_str());
+
+  arguments_.Write(to);
+
+  if (modifiers_ & Modifiers::IS_DEFAULT)
+    to->Write(" = default");
+
+  to->Write(";\n");
+}
+
+MacroDecl::MacroDecl(const std::string& name, ArgList&& arg_list)
+    : name_(name),
+      arguments_(std::move(arg_list)) {}
+
+void MacroDecl::Write(CodeWriter* to) const {
+  to->Write("%s", name_.c_str());
+  arguments_.Write(to);
+  to->Write("\n");
+}
+
+MethodDecl::MethodDecl(const std::string& return_type,
+                       const std::string& name,
+                       ArgList&& arg_list)
+    : MethodDecl(return_type, name, std::move(arg_list), 0u) {}
+
+MethodDecl::MethodDecl(const std::string& return_type,
+                       const std::string& name,
+                       ArgList&& arg_list,
+                       uint32_t modifiers)
+    : return_type_(return_type),
+      name_(name),
+      arguments_(std::move(arg_list)),
+      is_const_(modifiers & IS_CONST),
+      is_virtual_(modifiers & IS_VIRTUAL),
+      is_override_(modifiers & IS_OVERRIDE),
+      is_pure_virtual_(modifiers & IS_PURE_VIRTUAL),
+      is_static_(modifiers & IS_STATIC) {}
+
+void MethodDecl::Write(CodeWriter* to) const {
+  if (is_virtual_)
+    to->Write("virtual ");
+
+  if (is_static_)
+    to->Write("static ");
+
+  to->Write("%s %s", return_type_.c_str(), name_.c_str());
+
+  arguments_.Write(to);
+
+  if (is_const_)
+    to->Write(" const");
+
+  if (is_override_)
+    to->Write(" override");
+
+  if (is_pure_virtual_)
+    to->Write(" = 0");
+
+  to->Write(";\n");
+}
+
+void StatementBlock::AddStatement(unique_ptr<AstNode> statement) {
+  statements_.push_back(std::move(statement));
+}
+
+void StatementBlock::AddStatement(AstNode* statement) {
+  statements_.emplace_back(statement);
+}
+
+void StatementBlock::AddLiteral(const std::string& expression_str,
+                                bool add_semicolon) {
+  if (add_semicolon) {
+    statements_.push_back(unique_ptr<AstNode>(new Statement(expression_str)));
+  } else {
+    statements_.push_back(unique_ptr<AstNode>(
+        new LiteralExpression(expression_str)));
+  }
+}
+
+void StatementBlock::Write(CodeWriter* to) const {
+  to->Write("{\n");
+  for (const auto& statement : statements_) {
+    statement->Write(to);
+  }
+  to->Write("}\n");
+}
+
+ConstructorImpl::ConstructorImpl(const string& class_name,
+                                 ArgList&& arg_list,
+                                 const vector<string>& initializer_list)
+      : class_name_(class_name),
+        arguments_(std::move(arg_list)),
+        initializer_list_(initializer_list) {}
+
+void ConstructorImpl::Write(CodeWriter* to) const {
+  to->Write("%s::%s", class_name_.c_str(), class_name_.c_str());
+  arguments_.Write(to);
+  to->Write("\n");
+
+  bool is_first = true;
+  for (const string& i : initializer_list_) {
+    if (is_first) {
+      to->Write("    : %s", i.c_str());
+    } else {
+      to->Write(",\n      %s", i.c_str());
+    }
+    is_first = false;
+  }
+
+  body_.Write(to);
+}
+
+MethodImpl::MethodImpl(const string& return_type,
+                       const string& class_name,
+                       const string& method_name,
+                       ArgList&& arg_list,
+                       bool is_const_method)
+    : return_type_(return_type),
+      method_name_(method_name),
+      arguments_(std::move(arg_list)),
+      is_const_method_(is_const_method) {
+  if (!class_name.empty()) {
+    method_name_ = class_name + "::" + method_name;
+  }
+}
+
+StatementBlock* MethodImpl::GetStatementBlock() {
+  return &statements_;
+}
+
+void MethodImpl::Write(CodeWriter* to) const {
+  to->Write("%s %s", return_type_.c_str(), method_name_.c_str());
+  arguments_.Write(to);
+  to->Write("%s ", (is_const_method_) ? " const" : "");
+  statements_.Write(to);
+}
+
+SwitchStatement::SwitchStatement(const std::string& expression)
+    : switch_expression_(expression) {}
+
+StatementBlock* SwitchStatement::AddCase(const string& value_expression) {
+  auto it = std::find(case_values_.begin(), case_values_.end(), value_expression);
+  if (it != case_values_.end()) {
+    LOG(ERROR) << "internal error: duplicate switch case labels";
+    return nullptr;
+  }
+  StatementBlock* ret = new StatementBlock();
+  case_values_.push_back(value_expression);
+  case_logic_.push_back(unique_ptr<StatementBlock>{ret});
+  return ret;
+}
+
+void SwitchStatement::Write(CodeWriter* to) const {
+  to->Write("switch (%s) {\n", switch_expression_.c_str());
+  for (size_t i = 0; i < case_values_.size(); ++i) {
+    const string& case_value = case_values_[i];
+    const unique_ptr<StatementBlock>& statements = case_logic_[i];
+    if (case_value.empty()) {
+      to->Write("default:\n");
+    } else {
+      to->Write("case %s:\n", case_value.c_str());
+    }
+    statements->Write(to);
+    to->Write("break;\n");
+  }
+  to->Write("}\n");
+}
+
+
+Assignment::Assignment(const std::string& left, const std::string& right)
+    : Assignment(left, new LiteralExpression{right}) {}
+
+Assignment::Assignment(const std::string& left, AstNode* right)
+    : lhs_(left),
+      rhs_(right) {}
+
+void Assignment::Write(CodeWriter* to) const {
+  to->Write("%s = ", lhs_.c_str());
+  rhs_->Write(to);
+  to->Write(";\n");
+}
+
+MethodCall::MethodCall(const std::string& method_name,
+                       const std::string& single_argument)
+    : MethodCall(method_name, ArgList{single_argument}) {}
+
+MethodCall::MethodCall(const std::string& method_name,
+                       ArgList&& arg_list)
+    : method_name_(method_name),
+      arguments_{std::move(arg_list)} {}
+
+void MethodCall::Write(CodeWriter* to) const {
+  to->Write("%s", method_name_.c_str());
+  arguments_.Write(to);
+}
+
+IfStatement::IfStatement(AstNode* expression, bool invert_expression)
+    : expression_(expression),
+      invert_expression_(invert_expression) {}
+
+void IfStatement::Write(CodeWriter* to) const {
+  to->Write("if (%s", (invert_expression_) ? "!(" : "");
+  expression_->Write(to);
+  to->Write(")%s ", (invert_expression_) ? ")" : "");
+  on_true_.Write(to);
+
+  if (!on_false_.Empty()) {
+    to->Write("else ");
+    on_false_.Write(to);
+  }
+}
+
+Statement::Statement(unique_ptr<AstNode> expression)
+    : expression_(std::move(expression)) {}
+
+Statement::Statement(AstNode* expression) : expression_(expression) {}
+
+Statement::Statement(const string& expression)
+    : expression_(new LiteralExpression(expression)) {}
+
+void Statement::Write(CodeWriter* to) const {
+  expression_->Write(to);
+  to->Write(";\n");
+}
+
+Comparison::Comparison(AstNode* lhs, const string& comparison, AstNode* rhs)
+    : left_(lhs),
+      right_(rhs),
+      operator_(comparison) {}
+
+void Comparison::Write(CodeWriter* to) const {
+  to->Write("((");
+  left_->Write(to);
+  to->Write(") %s (", operator_.c_str());
+  right_->Write(to);
+  to->Write("))");
+}
+
+LiteralExpression::LiteralExpression(const std::string& expression)
+    : expression_(expression) {}
+
+void LiteralExpression::Write(CodeWriter* to) const {
+  to->Write("%s", expression_.c_str());
+}
+
+CppNamespace::CppNamespace(const std::string& name,
+                           std::vector<unique_ptr<Declaration>> declarations)
+    : declarations_(std::move(declarations)),
+      name_(name) {}
+
+CppNamespace::CppNamespace(const std::string& name,
+                           unique_ptr<Declaration> declaration)
+    : name_(name) {
+  declarations_.push_back(std::move(declaration));
+}
+CppNamespace::CppNamespace(const std::string& name)
+    : name_(name) {}
+
+void CppNamespace::Write(CodeWriter* to) const {
+  to->Write("namespace %s {\n\n", name_.c_str());
+
+  for (const auto& dec : declarations_) {
+    dec->Write(to);
+    to->Write("\n");
+  }
+
+  to->Write("}  // namespace %s\n", name_.c_str());
+}
+
+Document::Document(const std::vector<std::string>& include_list,
+                   unique_ptr<CppNamespace> a_namespace)
+    : include_list_(include_list),
+      namespace_(std::move(a_namespace)) {}
+
+void Document::Write(CodeWriter* to) const {
+  for (const auto& include : include_list_) {
+    to->Write("#include <%s>\n", include.c_str());
+  }
+  to->Write("\n");
+
+  namespace_->Write(to);
+}
+
+CppHeader::CppHeader(const std::string& include_guard,
+                     const std::vector<std::string>& include_list,
+                     unique_ptr<CppNamespace> a_namespace)
+    : Document(include_list, std::move(a_namespace)),
+      include_guard_(include_guard) {}
+
+void CppHeader::Write(CodeWriter* to) const {
+  to->Write("#ifndef %s\n", include_guard_.c_str());
+  to->Write("#define %s\n\n", include_guard_.c_str());
+
+  Document::Write(to);
+  to->Write("\n");
+
+  to->Write("#endif  // %s\n", include_guard_.c_str());
+}
+
+CppSource::CppSource(const std::vector<std::string>& include_list,
+                     unique_ptr<CppNamespace> a_namespace)
+    : Document(include_list, std::move(a_namespace)) {}
+
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/ast_cpp.h b/aidl/ast_cpp.h
new file mode 100644
index 0000000..bb251ec
--- /dev/null
+++ b/aidl/ast_cpp.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_AST_CPP_H_
+#define AIDL_AST_CPP_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace aidl {
+class CodeWriter;
+}  // namespace aidl
+}  // namespace android
+
+namespace android {
+namespace aidl {
+namespace cpp {
+
+class AstNode {
+ public:
+  AstNode() = default;
+  virtual ~AstNode() = default;
+  virtual void Write(CodeWriter* to) const = 0;
+};  // class AstNode
+
+class Declaration : public AstNode {
+ public:
+  Declaration() = default;
+  virtual ~Declaration() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Declaration);
+};  // class Declaration
+
+class ClassDecl : public Declaration {
+ public:
+  ClassDecl(const std::string& name,
+            const std::string& parent);
+  ClassDecl(const std::string& name,
+            const std::string& parent,
+            std::vector<std::unique_ptr<Declaration>> public_members,
+            std::vector<std::unique_ptr<Declaration>> private_members);
+  virtual ~ClassDecl() = default;
+
+  void Write(CodeWriter* to) const override;
+
+  void AddPublic(std::unique_ptr<Declaration> member);
+  void AddPrivate(std::unique_ptr<Declaration> member);
+
+ private:
+  std::string name_;
+  std::string parent_;
+  std::vector<std::unique_ptr<Declaration>> public_members_;
+  std::vector<std::unique_ptr<Declaration>> private_members_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClassDecl);
+};  // class ClassDecl
+
+class Enum : public Declaration {
+ public:
+  Enum(const std::string& name, const std::string& base_type);
+  explicit Enum(const std::string& name);
+  virtual ~Enum() = default;
+
+  bool HasValues() const { return !fields_.empty(); }
+  void Write(CodeWriter* to) const override;
+
+  void AddValue(const std::string& key, const std::string& value);
+
+ private:
+  struct EnumField {
+    EnumField(const std::string& k, const std::string& v);
+    const std::string key;
+    const std::string value;
+  };
+
+  std::string enum_name_;
+  std::string underlying_type_;
+  std::vector<EnumField> fields_;
+
+  DISALLOW_COPY_AND_ASSIGN(Enum);
+};  // class Enum
+
+class ArgList : public AstNode {
+ public:
+  ArgList() = default;
+  explicit ArgList(const std::string& single_argument);
+  explicit ArgList(const std::vector<std::string>& arg_list);
+  explicit ArgList(std::vector<std::unique_ptr<AstNode>> arg_list);
+  ArgList(ArgList&& arg_list);
+  virtual ~ArgList() = default;
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::vector<std::unique_ptr<AstNode>> arguments_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArgList);
+};  // class ArgList
+
+class ConstructorDecl : public Declaration {
+ public:
+  enum Modifiers {
+    IS_VIRTUAL = 1 << 0,
+    IS_DEFAULT = 1 << 1,
+    IS_EXPLICIT = 1 << 2,
+  };
+
+  ConstructorDecl(const std::string& name,
+                  ArgList&& arg_list);
+  ConstructorDecl(const std::string& name,
+                  ArgList&& arg_list,
+                  uint32_t modifiers);
+
+  virtual ~ConstructorDecl() = default;
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string name_;
+  const ArgList arguments_;
+  const uint32_t modifiers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConstructorDecl);
+};  // class ConstructorDecl
+
+class MacroDecl : public Declaration {
+ public:
+  MacroDecl(const std::string& name, ArgList&& arg_list);
+  virtual ~MacroDecl() = default;
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string name_;
+  const ArgList arguments_;
+
+  DISALLOW_COPY_AND_ASSIGN(MacroDecl);
+};  // class MacroDecl
+
+class MethodDecl : public Declaration {
+ public:
+  enum Modifiers {
+    IS_CONST = 1 << 0,
+    IS_VIRTUAL = 1 << 1,
+    IS_OVERRIDE = 1 << 2,
+    IS_PURE_VIRTUAL = 1 << 3,
+    IS_STATIC = 1 << 4,
+  };
+
+  MethodDecl(const std::string& return_type,
+             const std::string& name,
+             ArgList&& arg_list);
+  MethodDecl(const std::string& return_type,
+             const std::string& name,
+             ArgList&& arg_list,
+             uint32_t modifiers);
+  virtual ~MethodDecl() = default;
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string return_type_;
+  const std::string name_;
+  const ArgList arguments_;
+  bool is_const_ = false;
+  bool is_virtual_ = false;
+  bool is_override_ = false;
+  bool is_pure_virtual_ = false;
+  bool is_static_ = true;
+
+  DISALLOW_COPY_AND_ASSIGN(MethodDecl);
+};  // class MethodDecl
+
+class StatementBlock : public Declaration {
+ public:
+  StatementBlock() = default;
+  virtual ~StatementBlock() = default;
+
+  void AddStatement(std::unique_ptr<AstNode> statement);
+  void AddStatement(AstNode* statement);  // Takes ownership
+  void AddLiteral(const std::string& expression, bool add_semicolon = true);
+  bool Empty() const { return statements_.empty(); }
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::vector<std::unique_ptr<AstNode>> statements_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatementBlock);
+};  // class StatementBlock
+
+class ConstructorImpl : public Declaration {
+ public:
+  ConstructorImpl(const std::string& class_name,
+                  ArgList&& arg_list,
+                  const std::vector<std::string>& initializer_list);
+  virtual ~ConstructorImpl() = default;
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::string class_name_;
+  ArgList arguments_;
+  std::vector<std::string> initializer_list_;
+  StatementBlock body_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConstructorImpl);
+};  // class ConstructorImpl
+
+class MethodImpl : public Declaration {
+ public:
+  // Passing an empty class name causes the method to be declared as a normal
+  // function (ie. no ClassName:: qualifier).
+  MethodImpl(const std::string& return_type,
+             const std::string& class_name,
+             const std::string& method_name,
+             ArgList&& arg_list,
+             bool is_const_method = false);
+  virtual ~MethodImpl() = default;
+
+  // MethodImpl retains ownership of the statement block.
+  StatementBlock* GetStatementBlock();
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::string return_type_;
+  std::string method_name_;
+  const ArgList arguments_;
+  StatementBlock statements_;
+  bool is_const_method_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(MethodImpl);
+};  // class MethodImpl
+
+class SwitchStatement : public AstNode {
+ public:
+  explicit SwitchStatement(const std::string& expression);
+  virtual ~SwitchStatement() = default;
+
+  // Add a case statement and return a pointer code block corresponding
+  // to the case.  The switch statement will add a break statement
+  // after the code block by default to prevent accidental fall-through.
+  // Returns nullptr on duplicate value expressions (by strcmp, not value
+  // equivalence).
+  StatementBlock* AddCase(const std::string& value_expression);
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string switch_expression_;
+  std::vector<std::string> case_values_;
+  std::vector<std::unique_ptr<StatementBlock>> case_logic_;
+
+  DISALLOW_COPY_AND_ASSIGN(SwitchStatement);
+};  // class SwitchStatement
+
+class Assignment : public AstNode {
+ public:
+  Assignment(const std::string& left, const std::string& right);
+  Assignment(const std::string& left, AstNode* right);
+  ~Assignment() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string lhs_;
+  std::unique_ptr<AstNode> rhs_;
+
+  DISALLOW_COPY_AND_ASSIGN(Assignment);
+};  // class Assignment
+
+class MethodCall : public AstNode {
+ public:
+  MethodCall(const std::string& method_name,
+             const std::string& single_argument);
+  MethodCall(const std::string& method_name, ArgList&& arg_list);
+  ~MethodCall() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string method_name_;
+  const ArgList arguments_;
+
+  DISALLOW_COPY_AND_ASSIGN(MethodCall);
+};  // class MethodCall
+
+class IfStatement : public AstNode {
+ public:
+  explicit IfStatement(AstNode* expression,
+              bool invert_expression = false);
+  virtual ~IfStatement() = default;
+  StatementBlock* OnTrue() { return &on_true_; }
+  StatementBlock* OnFalse() { return &on_false_; }
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::unique_ptr<AstNode> expression_;
+  bool invert_expression_ = false;
+  StatementBlock on_true_;
+  StatementBlock on_false_;
+
+  DISALLOW_COPY_AND_ASSIGN(IfStatement);
+};  // class IfStatement
+
+class Statement : public AstNode {
+ public:
+  explicit Statement(std::unique_ptr<AstNode> expression);
+  explicit Statement(AstNode* expression);  // Takes possession.
+  explicit Statement(const std::string& expression);
+  ~Statement() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::unique_ptr<AstNode> expression_;
+
+  DISALLOW_COPY_AND_ASSIGN(Statement);
+};  // class Statement
+
+class Comparison : public AstNode {
+ public:
+  Comparison(AstNode* lhs, const std::string& comparison, AstNode* rhs);
+  ~Comparison() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::unique_ptr<AstNode> left_;
+  std::unique_ptr<AstNode> right_;
+  const std::string operator_;
+
+  DISALLOW_COPY_AND_ASSIGN(Comparison);
+};  // class Comparison
+
+class LiteralExpression : public AstNode {
+ public:
+  explicit LiteralExpression(const std::string& expression);
+  ~LiteralExpression() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string expression_;
+
+  DISALLOW_COPY_AND_ASSIGN(LiteralExpression);
+};  // class LiteralExpression
+
+class CppNamespace : public Declaration {
+ public:
+  CppNamespace(const std::string& name,
+               std::vector<std::unique_ptr<Declaration>> declarations);
+  CppNamespace(const std::string& name,
+               std::unique_ptr<Declaration> declaration);
+  explicit CppNamespace(const std::string& name);
+  virtual ~CppNamespace() = default;
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::vector<std::unique_ptr<Declaration>> declarations_;
+  std::string name_;
+
+  DISALLOW_COPY_AND_ASSIGN(CppNamespace);
+};  // class CppNamespace
+
+class Document : public AstNode {
+ public:
+  Document(const std::vector<std::string>& include_list,
+           std::unique_ptr<CppNamespace> a_namespace);
+
+  void Write(CodeWriter* to) const override;
+
+ private:
+  std::vector<std::string> include_list_;
+  std::unique_ptr<CppNamespace> namespace_;
+
+  DISALLOW_COPY_AND_ASSIGN(Document);
+};  // class Document
+
+class CppHeader final : public Document {
+ public:
+  CppHeader(const std::string& include_guard,
+            const std::vector<std::string>& include_list,
+            std::unique_ptr<CppNamespace> a_namespace);
+  void Write(CodeWriter* to) const override;
+
+ private:
+  const std::string include_guard_;
+
+  DISALLOW_COPY_AND_ASSIGN(CppHeader);
+};  // class CppHeader
+
+class CppSource final : public Document {
+ public:
+  CppSource(const std::vector<std::string>& include_list,
+            std::unique_ptr<CppNamespace> a_namespace);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CppSource);
+};  // class CppSource
+
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
+
+#endif // AIDL_AST_CPP_H_
diff --git a/aidl/ast_cpp_unittest.cpp b/aidl/ast_cpp_unittest.cpp
new file mode 100644
index 0000000..aee23b7
--- /dev/null
+++ b/aidl/ast_cpp_unittest.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "ast_cpp.h"
+#include "code_writer.h"
+
+using std::string;
+using std::vector;
+using std::unique_ptr;
+
+namespace android {
+namespace aidl {
+namespace cpp {
+namespace {
+
+const char kExpectedHeaderOutput[] =
+R"(#ifndef HEADER_INCLUDE_GUARD_H_
+#define HEADER_INCLUDE_GUARD_H_
+
+#include <string>
+#include <memory>
+
+namespace android {
+
+namespace test {
+
+class TestClass {
+public:
+void NormalMethod(int normalarg, float normal2);
+virtual void SubMethod(int subarg) const;
+};  // class TestClass
+
+class TestSubClass : public TestClass {
+public:
+virtual void SubMethod(int subarg) const;
+};  // class TestSubClass
+
+}  // namespace test
+
+}  // namespace android
+
+#endif  // HEADER_INCLUDE_GUARD_H_
+)";
+
+const char kExpectedEnumOutput[] =
+R"(enum Foo {
+  BAR = 42,
+  BAZ,
+};
+)";
+
+const char kExpectedSwitchOutput[] =
+R"(switch (var) {
+case 2:
+{
+baz;
+}
+break;
+case 1:
+{
+foo;
+bar;
+}
+break;
+}
+)";
+
+const char kExpectedMethodImplOutput[] =
+R"(return_type ClassName::MethodName(arg 1, arg 2, arg 3) const {
+foo;
+bar;
+}
+)";
+}  // namespace
+
+class AstCppTests : public ::testing::Test {
+ protected:
+  void CompareGeneratedCode(const AstNode& node,
+                            const string& expected_output) {
+    string actual_output;
+    CodeWriterPtr writer = GetStringWriter(&actual_output);
+    node.Write(writer.get());
+    EXPECT_EQ(expected_output, actual_output);
+  }
+};  // class AstCppTests
+
+
+TEST_F(AstCppTests, GeneratesHeader) {
+  unique_ptr<MethodDecl> norm{new MethodDecl(
+      "void", "NormalMethod",
+      ArgList{vector<string>{"int normalarg", "float normal2"}})};
+  unique_ptr<MethodDecl> sub{
+      new MethodDecl("void", "SubMethod",
+                     ArgList{ "int subarg" },
+                     MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
+  unique_ptr<MethodDecl> sub2{
+      new MethodDecl("void", "SubMethod",
+                     ArgList{ "int subarg" },
+                     MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)};
+  vector<unique_ptr<Declaration>> test_methods;
+  test_methods.push_back(std::move(norm));
+  test_methods.push_back(std::move(sub));
+
+  vector<unique_ptr<Declaration>> test_sub_methods;
+  test_sub_methods.push_back(std::move(sub2));
+
+  unique_ptr<Declaration> test{new ClassDecl { "TestClass", "",
+      std::move(test_methods), {} }};
+
+  unique_ptr<Declaration> test_sub{new ClassDecl { "TestSubClass",
+      "TestClass", std::move(test_sub_methods), {} }};
+
+  vector<unique_ptr<Declaration>> classes;
+  classes.push_back(std::move(test));
+  classes.push_back(std::move(test_sub));
+
+  unique_ptr<CppNamespace> test_ns{new CppNamespace {"test",
+      std::move(classes)}};
+
+  vector<unique_ptr<Declaration>> test_ns_vec;
+  test_ns_vec.push_back(std::move(test_ns));
+
+  unique_ptr<CppNamespace> android_ns{new CppNamespace {"android",
+      std::move(test_ns_vec) }};
+
+  CppHeader cpp_header{"HEADER_INCLUDE_GUARD_H_", {"string", "memory"},
+      std::move(android_ns) };
+  CompareGeneratedCode(cpp_header, kExpectedHeaderOutput);
+}
+
+TEST_F(AstCppTests, GeneratesEnum) {
+  Enum e("Foo");
+  e.AddValue("BAR", "42");
+  e.AddValue("BAZ", "");
+  CompareGeneratedCode(e, kExpectedEnumOutput);
+}
+
+TEST_F(AstCppTests, GeneratesArgList) {
+  ArgList simple("foo");
+  CompareGeneratedCode(simple, "(foo)");
+  ArgList compound({"foo", "bar", "baz"});
+  CompareGeneratedCode(compound, "(foo, bar, baz)");
+  std::vector<unique_ptr<AstNode>> args;
+  args.emplace_back(new LiteralExpression("foo()"));
+  ArgList nested(std::move(args));
+  CompareGeneratedCode(nested, "(foo())");
+}
+
+TEST_F(AstCppTests, GeneratesStatement) {
+  Statement s(new LiteralExpression("foo"));
+  CompareGeneratedCode(s, "foo;\n");
+}
+
+TEST_F(AstCppTests, GeneratesComparison) {
+  Comparison c(
+      new LiteralExpression("lhs"), "&&", new LiteralExpression("rhs"));
+  CompareGeneratedCode(c, "((lhs) && (rhs))");
+}
+
+TEST_F(AstCppTests, GeneratesStatementBlock) {
+  StatementBlock block;
+  block.AddStatement(unique_ptr<AstNode>(new Statement("foo")));
+  block.AddStatement(unique_ptr<AstNode>(new Statement("bar")));
+  CompareGeneratedCode(block, "{\nfoo;\nbar;\n}\n");
+}
+
+TEST_F(AstCppTests, GeneratesConstructorImpl) {
+  ConstructorImpl c("ClassName", ArgList({"a", "b", "c"}),
+                    {"baz_(foo)", "bar_(blah)"});
+  string expected = R"(ClassName::ClassName(a, b, c)
+    : baz_(foo),
+      bar_(blah){
+}
+)";
+  CompareGeneratedCode(c, expected);
+}
+
+TEST_F(AstCppTests, GeneratesAssignment) {
+  Assignment simple("foo", "8");
+  CompareGeneratedCode(simple, "foo = 8;\n");
+  Assignment less_simple("foo", new MethodCall("f", "8"));
+  CompareGeneratedCode(less_simple, "foo = f(8);\n");
+}
+
+TEST_F(AstCppTests, GeneratesMethodCall) {
+  MethodCall single("single", "arg");
+  CompareGeneratedCode(single, "single(arg)");
+  MethodCall multi(
+      "multi",
+      ArgList({"has", "some", "args"}));
+  CompareGeneratedCode(multi, "multi(has, some, args)");
+}
+
+TEST_F(AstCppTests, GeneratesIfStatement) {
+  IfStatement s(new LiteralExpression("foo"));
+  s.OnTrue()->AddLiteral("on true1");
+  s.OnFalse()->AddLiteral("on false");
+  CompareGeneratedCode(s, "if (foo) {\non true1;\n}\nelse {\non false;\n}\n");
+
+  IfStatement s2(new LiteralExpression("bar"));
+  s2.OnTrue()->AddLiteral("on true1");
+  CompareGeneratedCode(s2, "if (bar) {\non true1;\n}\n");
+}
+
+TEST_F(AstCppTests, GeneratesSwitchStatement) {
+  SwitchStatement s("var");
+  // These are intentionally out of alphanumeric order.  We're testing
+  // that switch respects case addition order.
+  auto case2 = s.AddCase("2");
+  case2->AddStatement(unique_ptr<AstNode>{new Statement{"baz"}});
+  auto case1 = s.AddCase("1");
+  case1->AddStatement(unique_ptr<AstNode>{new Statement{"foo"}});
+  case1->AddStatement(unique_ptr<AstNode>{new Statement{"bar"}});
+  CompareGeneratedCode(s, kExpectedSwitchOutput);
+}
+
+TEST_F(AstCppTests, GeneratesMethodImpl) {
+  MethodImpl m{"return_type", "ClassName", "MethodName",
+               ArgList{{"arg 1", "arg 2", "arg 3"}},
+               true};
+  auto b = m.GetStatementBlock();
+  b->AddLiteral("foo");
+  b->AddLiteral("bar");
+  CompareGeneratedCode(m, kExpectedMethodImplOutput);
+}
+
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/ast_java.cpp b/aidl/ast_java.cpp
new file mode 100644
index 0000000..1ba723c
--- /dev/null
+++ b/aidl/ast_java.cpp
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ast_java.h"
+
+#include "code_writer.h"
+#include "type_java.h"
+
+using std::vector;
+using std::string;
+
+namespace android {
+namespace aidl {
+namespace java {
+
+void WriteModifiers(CodeWriter* to, int mod, int mask) {
+  int m = mod & mask;
+
+  if (m & OVERRIDE) {
+    to->Write("@Override ");
+  }
+
+  if ((m & SCOPE_MASK) == PUBLIC) {
+    to->Write("public ");
+  } else if ((m & SCOPE_MASK) == PRIVATE) {
+    to->Write("private ");
+  } else if ((m & SCOPE_MASK) == PROTECTED) {
+    to->Write("protected ");
+  }
+
+  if (m & STATIC) {
+    to->Write("static ");
+  }
+
+  if (m & FINAL) {
+    to->Write("final ");
+  }
+
+  if (m & ABSTRACT) {
+    to->Write("abstract ");
+  }
+}
+
+void WriteArgumentList(CodeWriter* to, const vector<Expression*>& arguments) {
+  size_t N = arguments.size();
+  for (size_t i = 0; i < N; i++) {
+    arguments[i]->Write(to);
+    if (i != N - 1) {
+      to->Write(", ");
+    }
+  }
+}
+
+Field::Field(int m, Variable* v) : ClassElement(), modifiers(m), variable(v) {}
+
+void Field::Write(CodeWriter* to) const {
+  if (this->comment.length() != 0) {
+    to->Write("%s\n", this->comment.c_str());
+  }
+  WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
+  to->Write("%s %s", this->variable->type->JavaType().c_str(),
+            this->variable->name.c_str());
+  if (this->value.length() != 0) {
+    to->Write(" = %s", this->value.c_str());
+  }
+  to->Write(";\n");
+}
+
+LiteralExpression::LiteralExpression(const string& v) : value(v) {}
+
+void LiteralExpression::Write(CodeWriter* to) const {
+  to->Write("%s", this->value.c_str());
+}
+
+StringLiteralExpression::StringLiteralExpression(const string& v) : value(v) {}
+
+void StringLiteralExpression::Write(CodeWriter* to) const {
+  to->Write("\"%s\"", this->value.c_str());
+}
+
+Variable::Variable(const Type* t, const string& n)
+    : type(t), name(n), dimension(0) {}
+
+Variable::Variable(const Type* t, const string& n, int d)
+    : type(t), name(n), dimension(d) {}
+
+void Variable::WriteDeclaration(CodeWriter* to) const {
+  string dim;
+  for (int i = 0; i < this->dimension; i++) {
+    dim += "[]";
+  }
+  to->Write("%s%s %s", this->type->JavaType().c_str(), dim.c_str(),
+            this->name.c_str());
+}
+
+void Variable::Write(CodeWriter* to) const { to->Write("%s", name.c_str()); }
+
+FieldVariable::FieldVariable(Expression* o, const string& n)
+    : object(o), clazz(NULL), name(n) {}
+
+FieldVariable::FieldVariable(const Type* c, const string& n)
+    : object(NULL), clazz(c), name(n) {}
+
+void FieldVariable::Write(CodeWriter* to) const {
+  if (this->object != NULL) {
+    this->object->Write(to);
+  } else if (this->clazz != NULL) {
+    to->Write("%s", this->clazz->JavaType().c_str());
+  }
+  to->Write(".%s", name.c_str());
+}
+
+void StatementBlock::Write(CodeWriter* to) const {
+  to->Write("{\n");
+  int N = this->statements.size();
+  for (int i = 0; i < N; i++) {
+    this->statements[i]->Write(to);
+  }
+  to->Write("}\n");
+}
+
+void StatementBlock::Add(Statement* statement) {
+  this->statements.push_back(statement);
+}
+
+void StatementBlock::Add(Expression* expression) {
+  this->statements.push_back(new ExpressionStatement(expression));
+}
+
+ExpressionStatement::ExpressionStatement(Expression* e) : expression(e) {}
+
+void ExpressionStatement::Write(CodeWriter* to) const {
+  this->expression->Write(to);
+  to->Write(";\n");
+}
+
+Assignment::Assignment(Variable* l, Expression* r)
+    : lvalue(l), rvalue(r), cast(NULL) {}
+
+Assignment::Assignment(Variable* l, Expression* r, const Type* c)
+    : lvalue(l), rvalue(r), cast(c) {}
+
+void Assignment::Write(CodeWriter* to) const {
+  this->lvalue->Write(to);
+  to->Write(" = ");
+  if (this->cast != NULL) {
+    to->Write("(%s)", this->cast->JavaType().c_str());
+  }
+  this->rvalue->Write(to);
+}
+
+MethodCall::MethodCall(const string& n) : name(n) {}
+
+MethodCall::MethodCall(const string& n, int argc = 0, ...) : name(n) {
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+MethodCall::MethodCall(Expression* o, const string& n) : obj(o), name(n) {}
+
+MethodCall::MethodCall(const Type* t, const string& n) : clazz(t), name(n) {}
+
+MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...)
+    : obj(o), name(n) {
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+MethodCall::MethodCall(const Type* t, const string& n, int argc = 0, ...)
+    : clazz(t), name(n) {
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+void MethodCall::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 MethodCall::Write(CodeWriter* to) const {
+  if (this->obj != NULL) {
+    this->obj->Write(to);
+    to->Write(".");
+  } else if (this->clazz != NULL) {
+    to->Write("%s.", this->clazz->JavaType().c_str());
+  }
+  to->Write("%s(", this->name.c_str());
+  WriteArgumentList(to, this->arguments);
+  to->Write(")");
+}
+
+Comparison::Comparison(Expression* l, const string& o, Expression* r)
+    : lvalue(l), op(o), rvalue(r) {}
+
+void Comparison::Write(CodeWriter* to) const {
+  to->Write("(");
+  this->lvalue->Write(to);
+  to->Write("%s", this->op.c_str());
+  this->rvalue->Write(to);
+  to->Write(")");
+}
+
+NewExpression::NewExpression(const Type* t) : type(t) {}
+
+NewExpression::NewExpression(const Type* t, int argc = 0, ...) : type(t) {
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
+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(CodeWriter* to) const {
+  to->Write("new %s(", this->type->InstantiableName().c_str());
+  WriteArgumentList(to, this->arguments);
+  to->Write(")");
+}
+
+NewArrayExpression::NewArrayExpression(const Type* t, Expression* s)
+    : type(t), size(s) {}
+
+void NewArrayExpression::Write(CodeWriter* to) const {
+  to->Write("new %s[", this->type->JavaType().c_str());
+  size->Write(to);
+  to->Write("]");
+}
+
+Ternary::Ternary(Expression* a, Expression* b, Expression* c)
+    : condition(a), ifpart(b), elsepart(c) {}
+
+void Ternary::Write(CodeWriter* to) const {
+  to->Write("((");
+  this->condition->Write(to);
+  to->Write(")?(");
+  this->ifpart->Write(to);
+  to->Write("):(");
+  this->elsepart->Write(to);
+  to->Write("))");
+}
+
+Cast::Cast(const Type* t, Expression* e) : type(t), expression(e) {}
+
+void Cast::Write(CodeWriter* to) const {
+  to->Write("((%s)", this->type->JavaType().c_str());
+  expression->Write(to);
+  to->Write(")");
+}
+
+VariableDeclaration::VariableDeclaration(Variable* l, Expression* r,
+                                         const Type* c)
+    : lvalue(l), cast(c), rvalue(r) {}
+
+VariableDeclaration::VariableDeclaration(Variable* l) : lvalue(l) {}
+
+void VariableDeclaration::Write(CodeWriter* to) const {
+  this->lvalue->WriteDeclaration(to);
+  if (this->rvalue != NULL) {
+    to->Write(" = ");
+    if (this->cast != NULL) {
+      to->Write("(%s)", this->cast->JavaType().c_str());
+    }
+    this->rvalue->Write(to);
+  }
+  to->Write(";\n");
+}
+
+void IfStatement::Write(CodeWriter* to) const {
+  if (this->expression != NULL) {
+    to->Write("if (");
+    this->expression->Write(to);
+    to->Write(") ");
+  }
+  this->statements->Write(to);
+  if (this->elseif != NULL) {
+    to->Write("else ");
+    this->elseif->Write(to);
+  }
+}
+
+ReturnStatement::ReturnStatement(Expression* e) : expression(e) {}
+
+void ReturnStatement::Write(CodeWriter* to) const {
+  to->Write("return ");
+  this->expression->Write(to);
+  to->Write(";\n");
+}
+
+void TryStatement::Write(CodeWriter* to) const {
+  to->Write("try ");
+  this->statements->Write(to);
+}
+
+CatchStatement::CatchStatement(Variable* e)
+    : statements(new StatementBlock), exception(e) {}
+
+void CatchStatement::Write(CodeWriter* to) const {
+  to->Write("catch ");
+  if (this->exception != NULL) {
+    to->Write("(");
+    this->exception->WriteDeclaration(to);
+    to->Write(") ");
+  }
+  this->statements->Write(to);
+}
+
+void FinallyStatement::Write(CodeWriter* to) const {
+  to->Write("finally ");
+  this->statements->Write(to);
+}
+
+Case::Case(const string& c) { cases.push_back(c); }
+
+void Case::Write(CodeWriter* to) const {
+  int N = this->cases.size();
+  if (N > 0) {
+    for (int i = 0; i < N; i++) {
+      string s = this->cases[i];
+      if (s.length() != 0) {
+        to->Write("case %s:\n", s.c_str());
+      } else {
+        to->Write("default:\n");
+      }
+    }
+  } else {
+    to->Write("default:\n");
+  }
+  statements->Write(to);
+}
+
+SwitchStatement::SwitchStatement(Expression* e) : expression(e) {}
+
+void SwitchStatement::Write(CodeWriter* to) const {
+  to->Write("switch (");
+  this->expression->Write(to);
+  to->Write(")\n{\n");
+  int N = this->cases.size();
+  for (int i = 0; i < N; i++) {
+    this->cases[i]->Write(to);
+  }
+  to->Write("}\n");
+}
+
+void Break::Write(CodeWriter* to) const { to->Write("break;\n"); }
+
+void Method::Write(CodeWriter* to) const {
+  size_t N, i;
+
+  if (this->comment.length() != 0) {
+    to->Write("%s\n", this->comment.c_str());
+  }
+
+  WriteModifiers(to, this->modifiers,
+                 SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
+
+  if (this->returnType != NULL) {
+    string dim;
+    for (i = 0; i < this->returnTypeDimension; i++) {
+      dim += "[]";
+    }
+    to->Write("%s%s ", this->returnType->JavaType().c_str(), dim.c_str());
+  }
+
+  to->Write("%s(", this->name.c_str());
+
+  N = this->parameters.size();
+  for (i = 0; i < N; i++) {
+    this->parameters[i]->WriteDeclaration(to);
+    if (i != N - 1) {
+      to->Write(", ");
+    }
+  }
+
+  to->Write(")");
+
+  N = this->exceptions.size();
+  for (i = 0; i < N; i++) {
+    if (i == 0) {
+      to->Write(" throws ");
+    } else {
+      to->Write(", ");
+    }
+    to->Write("%s", this->exceptions[i]->JavaType().c_str());
+  }
+
+  if (this->statements == NULL) {
+    to->Write(";\n");
+  } else {
+    to->Write("\n");
+    this->statements->Write(to);
+  }
+}
+
+void IntConstant::Write(CodeWriter* to) const {
+  WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS);
+  to->Write("int %s = %d;\n", name.c_str(), value);
+}
+
+void StringConstant::Write(CodeWriter* to) const {
+  WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS);
+  to->Write("String %s = %s;\n", name.c_str(), value.c_str());
+}
+
+void Class::Write(CodeWriter* to) const {
+  size_t N, i;
+
+  if (this->comment.length() != 0) {
+    to->Write("%s\n", this->comment.c_str());
+  }
+
+  WriteModifiers(to, this->modifiers, ALL_MODIFIERS);
+
+  if (this->what == Class::CLASS) {
+    to->Write("class ");
+  } else {
+    to->Write("interface ");
+  }
+
+  string name = this->type->JavaType();
+  size_t pos = name.rfind('.');
+  if (pos != string::npos) {
+    name = name.c_str() + pos + 1;
+  }
+
+  to->Write("%s", name.c_str());
+
+  if (this->extends != NULL) {
+    to->Write(" extends %s", this->extends->JavaType().c_str());
+  }
+
+  N = this->interfaces.size();
+  if (N != 0) {
+    if (this->what == Class::CLASS) {
+      to->Write(" implements");
+    } else {
+      to->Write(" extends");
+    }
+    for (i = 0; i < N; i++) {
+      to->Write(" %s", this->interfaces[i]->JavaType().c_str());
+    }
+  }
+
+  to->Write("\n");
+  to->Write("{\n");
+
+  N = this->elements.size();
+  for (i = 0; i < N; i++) {
+    this->elements[i]->Write(to);
+  }
+
+  to->Write("}\n");
+}
+
+static string escape_backslashes(const string& str) {
+  string result;
+  const size_t I = str.length();
+  for (size_t i = 0; i < I; i++) {
+    char c = str[i];
+    if (c == '\\') {
+      result += "\\\\";
+    } else {
+      result += c;
+    }
+  }
+  return result;
+}
+
+Document::Document(const std::string& comment,
+                   const std::string& package,
+                   const std::string& original_src,
+                   std::unique_ptr<Class> clazz)
+    : comment_(comment),
+      package_(package),
+      original_src_(original_src),
+      clazz_(std::move(clazz)) {
+}
+
+void Document::Write(CodeWriter* to) const {
+  if (!comment_.empty()) {
+    to->Write("%s\n", comment_.c_str());
+  }
+  to->Write(
+      "/*\n"
+      " * This file is auto-generated.  DO NOT MODIFY.\n"
+      " * Original file: %s\n"
+      " */\n",
+      escape_backslashes(original_src_).c_str());
+  if (!package_.empty()) {
+    to->Write("package %s;\n", package_.c_str());
+  }
+
+  if (clazz_) {
+    clazz_->Write(to);
+  }
+}
+
+}  // namespace java
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/ast_java.h b/aidl/ast_java.h
new file mode 100644
index 0000000..c5ded58
--- /dev/null
+++ b/aidl/ast_java.h
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_AST_JAVA_H_
+#define AIDL_AST_JAVA_H_
+
+#include <memory>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+enum {
+  PACKAGE_PRIVATE = 0x00000000,
+  PUBLIC = 0x00000001,
+  PRIVATE = 0x00000002,
+  PROTECTED = 0x00000003,
+  SCOPE_MASK = 0x00000003,
+
+  STATIC = 0x00000010,
+  FINAL = 0x00000020,
+  ABSTRACT = 0x00000040,
+
+  OVERRIDE = 0x00000100,
+
+  ALL_MODIFIERS = 0xffffffff
+};
+
+namespace android {
+namespace aidl {
+class CodeWriter;
+}  // namespace aidl
+}  // namespace android
+
+namespace android {
+namespace aidl {
+namespace java {
+
+class Type;
+
+// Write the modifiers that are set in both mod and mask
+void WriteModifiers(CodeWriter* to, int mod, int mask);
+
+struct ClassElement {
+  ClassElement() = default;
+  virtual ~ClassElement() = default;
+
+  virtual void Write(CodeWriter* to) const = 0;
+};
+
+struct Expression {
+  virtual ~Expression() = default;
+  virtual void Write(CodeWriter* to) const = 0;
+};
+
+struct LiteralExpression : public Expression {
+  std::string value;
+
+  explicit LiteralExpression(const std::string& value);
+  virtual ~LiteralExpression() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+// TODO: also escape the contents.  not needed for now
+struct StringLiteralExpression : public Expression {
+  std::string value;
+
+  explicit StringLiteralExpression(const std::string& value);
+  virtual ~StringLiteralExpression() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct Variable : public Expression {
+  const Type* type = nullptr;
+  std::string name;
+  int dimension = 0;
+
+  Variable() = default;
+  Variable(const Type* type, const std::string& name);
+  Variable(const Type* type, const std::string& name, int dimension);
+  virtual ~Variable() = default;
+
+  void WriteDeclaration(CodeWriter* to) const;
+  void Write(CodeWriter* to) const;
+};
+
+struct FieldVariable : public Expression {
+  Expression* object;
+  const Type* clazz;
+  std::string name;
+
+  FieldVariable(Expression* object, const std::string& name);
+  FieldVariable(const Type* clazz, const std::string& name);
+  virtual ~FieldVariable() = default;
+
+  void Write(CodeWriter* to) const;
+};
+
+struct Field : public ClassElement {
+  std::string comment;
+  int modifiers = 0;
+  Variable* variable = nullptr;
+  std::string value;
+
+  Field() = default;
+  Field(int modifiers, Variable* variable);
+  virtual ~Field() = default;
+
+  void Write(CodeWriter* to) const override;
+};
+
+struct Statement {
+  virtual ~Statement() = default;
+  virtual void Write(CodeWriter* to) const = 0;
+};
+
+struct StatementBlock : public Statement {
+  std::vector<Statement*> statements;
+
+  StatementBlock() = default;
+  virtual ~StatementBlock() = default;
+  void Write(CodeWriter* to) const override;
+
+  void Add(Statement* statement);
+  void Add(Expression* expression);
+};
+
+struct ExpressionStatement : public Statement {
+  Expression* expression;
+
+  explicit ExpressionStatement(Expression* expression);
+  virtual ~ExpressionStatement() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct Assignment : public Expression {
+  Variable* lvalue;
+  Expression* rvalue;
+  const Type* cast;
+
+  Assignment(Variable* lvalue, Expression* rvalue);
+  Assignment(Variable* lvalue, Expression* rvalue, const Type* cast);
+  virtual ~Assignment() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct MethodCall : public Expression {
+  Expression* obj = nullptr;
+  const Type* clazz = nullptr;
+  std::string name;
+  std::vector<Expression*> arguments;
+  std::vector<std::string> exceptions;
+
+  explicit MethodCall(const std::string& name);
+  MethodCall(const std::string& name, int argc, ...);
+  MethodCall(Expression* obj, const std::string& name);
+  MethodCall(const Type* clazz, const std::string& name);
+  MethodCall(Expression* obj, const std::string& name, int argc, ...);
+  MethodCall(const Type* clazz, const std::string& name, int argc, ...);
+  virtual ~MethodCall() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  void init(int n, va_list args);
+};
+
+struct Comparison : public Expression {
+  Expression* lvalue;
+  std::string op;
+  Expression* rvalue;
+
+  Comparison(Expression* lvalue, const std::string& op, Expression* rvalue);
+  virtual ~Comparison() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct NewExpression : public Expression {
+  const Type* type;
+  std::vector<Expression*> arguments;
+
+  explicit NewExpression(const Type* type);
+  NewExpression(const Type* type, int argc, ...);
+  virtual ~NewExpression() = default;
+  void Write(CodeWriter* to) const override;
+
+ private:
+  void init(int n, va_list args);
+};
+
+struct NewArrayExpression : public Expression {
+  const Type* type;
+  Expression* size;
+
+  NewArrayExpression(const Type* type, Expression* size);
+  virtual ~NewArrayExpression() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct Ternary : public Expression {
+  Expression* condition = nullptr;
+  Expression* ifpart = nullptr;
+  Expression* elsepart = nullptr;
+
+  Ternary() = default;
+  Ternary(Expression* condition, Expression* ifpart, Expression* elsepart);
+  virtual ~Ternary() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct Cast : public Expression {
+  const Type* type = nullptr;
+  Expression* expression = nullptr;
+
+  Cast() = default;
+  Cast(const Type* type, Expression* expression);
+  virtual ~Cast() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct VariableDeclaration : public Statement {
+  Variable* lvalue = nullptr;
+  const Type* cast = nullptr;
+  Expression* rvalue = nullptr;
+
+  explicit VariableDeclaration(Variable* lvalue);
+  VariableDeclaration(Variable* lvalue, Expression* rvalue,
+                      const Type* cast = NULL);
+  virtual ~VariableDeclaration() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct IfStatement : public Statement {
+  Expression* expression = nullptr;
+  StatementBlock* statements = new StatementBlock;
+  IfStatement* elseif = nullptr;
+
+  IfStatement() = default;
+  virtual ~IfStatement() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct ReturnStatement : public Statement {
+  Expression* expression;
+
+  explicit ReturnStatement(Expression* expression);
+  virtual ~ReturnStatement() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct TryStatement : public Statement {
+  StatementBlock* statements = new StatementBlock;
+
+  TryStatement() = default;
+  virtual ~TryStatement() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct CatchStatement : public Statement {
+  StatementBlock* statements;
+  Variable* exception;
+
+  explicit CatchStatement(Variable* exception);
+  virtual ~CatchStatement() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct FinallyStatement : public Statement {
+  StatementBlock* statements = new StatementBlock;
+
+  FinallyStatement() = default;
+  virtual ~FinallyStatement() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct Case {
+  std::vector<std::string> cases;
+  StatementBlock* statements = new StatementBlock;
+
+  Case() = default;
+  explicit Case(const std::string& c);
+  virtual ~Case() = default;
+  virtual void Write(CodeWriter* to) const;
+};
+
+struct SwitchStatement : public Statement {
+  Expression* expression;
+  std::vector<Case*> cases;
+
+  explicit SwitchStatement(Expression* expression);
+  virtual ~SwitchStatement() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct Break : public Statement {
+  Break() = default;
+  virtual ~Break() = default;
+  void Write(CodeWriter* to) const override;
+};
+
+struct Method : public ClassElement {
+  std::string comment;
+  int modifiers = 0;
+  const Type* returnType = nullptr;  // nullptr means constructor
+  size_t returnTypeDimension = 0;
+  std::string name;
+  std::vector<Variable*> parameters;
+  std::vector<const Type*> exceptions;
+  StatementBlock* statements = nullptr;
+
+  Method() = default;
+  virtual ~Method() = default;
+
+  void Write(CodeWriter* to) const override;
+};
+
+struct IntConstant : public ClassElement {
+  const std::string name;
+  const int value;
+
+  IntConstant(std::string name, int value)
+      : name(name), value(value) {}
+  virtual ~IntConstant() = default;
+
+  void Write(CodeWriter* to) const override;
+};
+
+struct StringConstant : public ClassElement {
+  const std::string name;
+  const std::string value;
+
+  StringConstant(std::string name, std::string value)
+      : name(name), value(value) {}
+  ~StringConstant() override = default;
+
+  void Write(CodeWriter* to) const override;
+};
+
+struct Class : public ClassElement {
+  enum { CLASS, INTERFACE };
+
+  std::string comment;
+  int modifiers = 0;
+  int what = CLASS;  // CLASS or INTERFACE
+  const Type* type = nullptr;
+  const Type* extends = nullptr;
+  std::vector<const Type*> interfaces;
+  std::vector<ClassElement*> elements;
+
+  Class() = default;
+  virtual ~Class() = default;
+
+  void Write(CodeWriter* to) const override;
+};
+
+class Document {
+ public:
+  Document(const std::string& comment,
+           const std::string& package,
+           const std::string& original_src,
+           std::unique_ptr<Class> clazz);
+  virtual ~Document() = default;
+  virtual void Write(CodeWriter* to) const;
+
+ private:
+  std::string comment_;
+  std::string package_;
+  std::string original_src_;
+  std::unique_ptr<Class> clazz_;
+};
+
+}  // namespace java
+}  // namespace aidl
+}  // namespace android
+
+#endif  // AIDL_AST_JAVA_H_
diff --git a/aidl/ast_java_unittest.cpp b/aidl/ast_java_unittest.cpp
new file mode 100644
index 0000000..b2aad23
--- /dev/null
+++ b/aidl/ast_java_unittest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "ast_java.h"
+#include "code_writer.h"
+#include "type_java.h"
+
+using std::string;
+
+namespace android {
+namespace aidl {
+namespace java {
+namespace {
+
+const char kExpectedClassOutput[] =
+R"(// class comment
+final class TestClass extends SuperClass
+{
+}
+)";
+
+}  // namespace
+
+TEST(AstJavaTests, GeneratesClass) {
+  JavaTypeNamespace types;
+  types.Init();
+  Type class_type(&types, "TestClass", ValidatableType::KIND_GENERATED,
+                  false, false);
+  Type extend_type(&types, "SuperClass", ValidatableType::KIND_BUILT_IN,
+                   false, false);
+  Class a_class;
+  a_class.comment = "// class comment";
+  a_class.modifiers = FINAL;
+  a_class.what = Class::CLASS;
+  a_class.type = &class_type;
+  a_class.extends = &extend_type;
+
+  string actual_output;
+  CodeWriterPtr writer = GetStringWriter(&actual_output);
+  a_class.Write(writer.get());
+  EXPECT_EQ(string(kExpectedClassOutput), actual_output);
+}
+
+}  // namespace java
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/code_writer.cpp b/aidl/code_writer.cpp
new file mode 100644
index 0000000..58b1dc1
--- /dev/null
+++ b/aidl/code_writer.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "code_writer.h"
+
+#include <iostream>
+#include <stdarg.h>
+
+#include <android-base/stringprintf.h>
+
+using std::cerr;
+using std::endl;
+
+namespace android {
+namespace aidl {
+
+namespace {
+
+class StringCodeWriter : public CodeWriter {
+ public:
+  explicit StringCodeWriter(std::string* output_buffer) : output_(output_buffer) {}
+  virtual ~StringCodeWriter() = default;
+
+  bool Write(const char* format, ...) override {
+    va_list ap;
+    va_start(ap, format);
+    android::base::StringAppendV(output_, format, ap);
+    va_end(ap);
+    return true;
+  }
+
+  bool Close() override { return true; }
+
+ private:
+  std::string* output_;
+};  // class StringCodeWriter
+
+class FileCodeWriter : public CodeWriter {
+ public:
+  FileCodeWriter(FILE* output_file, bool close_on_destruction)
+      : output_(output_file),
+        close_on_destruction_(close_on_destruction) {}
+  virtual ~FileCodeWriter() {
+    if (close_on_destruction_ && output_ != nullptr) {
+      fclose(output_);
+    }
+  }
+
+  bool Write(const char* format, ...) override {
+    bool success;
+    va_list ap;
+    va_start(ap, format);
+    success = vfprintf(output_, format, ap) >= 0;
+    va_end(ap);
+    no_error_ = no_error_ && success;
+    return success;
+  }
+
+  bool Close() override {
+    if (output_ != nullptr) {
+      no_error_ = fclose(output_) == 0 && no_error_;
+      output_ = nullptr;
+    }
+    return no_error_;
+  }
+
+ private:
+  bool no_error_ = true;
+  FILE* output_;
+  bool close_on_destruction_;
+};  // class StringCodeWriter
+
+}  // namespace
+
+CodeWriterPtr GetFileWriter(const std::string& output_file) {
+  CodeWriterPtr result;
+  FILE* to = nullptr;
+  bool close_on_destruction = true;
+  if (output_file == "-") {
+    to = stdout;
+    close_on_destruction = false;
+  } else {
+    // open file in binary mode to ensure that the tool produces the
+    // same output on all platforms !!
+    to = fopen(output_file.c_str(), "wb");
+  }
+
+  if (to != nullptr) {
+    result.reset(new FileCodeWriter(to, close_on_destruction));
+  } else {
+    cerr << "unable to open " << output_file << " for write" << endl;
+  }
+
+  return result;
+}
+
+CodeWriterPtr GetStringWriter(std::string* output_buffer) {
+  return CodeWriterPtr(new StringCodeWriter(output_buffer));
+}
+
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/code_writer.h b/aidl/code_writer.h
new file mode 100644
index 0000000..4b2fe16
--- /dev/null
+++ b/aidl/code_writer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_CODE_WRITER_H_
+#define AIDL_CODE_WRITER_H_
+
+#include <memory>
+#include <string>
+
+#include <stdio.h>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace aidl {
+
+class CodeWriter {
+ public:
+  // Write a formatted string to this writer in the usual printf sense.
+  // Returns false on error.
+  virtual bool Write(const char* format, ...) = 0;
+  virtual bool Close() = 0;
+  virtual ~CodeWriter() = default;
+};  // class CodeWriter
+
+using CodeWriterPtr = std::unique_ptr<CodeWriter>;
+
+// Get a CodeWriter that writes to |output_file|.
+CodeWriterPtr GetFileWriter(const std::string& output_file);
+
+// Get a CodeWriter that writes to a string buffer.
+// Caller retains ownership of the buffer.
+// The buffer must outlive the CodeWriter.
+CodeWriterPtr GetStringWriter(std::string* output_buffer);
+
+}  // namespace aidl
+}  // namespace android
+
+#endif // AIDL_CODE_WRITER_H_
diff --git a/aidl/docs/aidl-cpp.md b/aidl/docs/aidl-cpp.md
new file mode 100644
index 0000000..65cc8e4
--- /dev/null
+++ b/aidl/docs/aidl-cpp.md
@@ -0,0 +1,276 @@
+# Generating C++ Binder Interfaces with `aidl-cpp`
+
+## Background
+
+“aidl” refers to several related but distinct concepts:
+
+ - the AIDL interface [definition language](http://developer.android.com/guide/components/aidl.html)
+ - .aidl files (which contain AIDL)
+ - the aidl generator which transforms AIDL into client/server IPC interfaces
+
+The _aidl generator_ is a command line tool that generates client and server
+stubs for Binder interfaces from a specification in a file with the .aidl
+extension.  For Java interfaces, the executable is called `aidl` while for C++
+the binary is called `aidl-cpp`.  In this document, we’ll use AIDL to describe
+the language of .aidl files and _aidl generator_ to refer to the code generation
+tool that takes an .aidl file, parses the AIDL, and outputs code.
+
+Previously, the _aidl generator_ only generated Java interface/stub/proxy
+objects.  C++ Binder interfaces were handcrafted with various degrees of
+compatibility with the Java equivalents.  The Brillo project added support for
+generating C++ with the _aidl generator_.  This generated C++ is cross-language
+compatible (e.g. Java clients are tested to interoperate with native services).
+
+## Overview
+
+This document describes how C++ generation works with attention to:
+
+ - build interface
+ - cross-language type mapping
+ - implementing a generated interface
+ - C++ parcelables
+ - cross-language error reporting
+ - cross-language null reference handling
+
+## Detailed Design
+
+### Build Interface
+
+Write AIDL in .aidl files and add them to `LOCAL_SRC_FILES` in your Android.mk.
+If your build target is a binary (e.g. you include `$(BUILD_SHARED_LIBRARY)`),
+then the generated code will be C++, not Java.
+
+AIDL definitions should be hosted from the same repository as the
+implementation.  Any system that needs the definition will also need the
+implementation (for both parcelables and interface).  If there are multiple
+implementations (i.e. one in Java and one in C++), keep the definition with the
+native implementation.  Android
+[now has systems](https://developers.google.com/brillo/?hl=en) that run the
+native components of the system without the Java.
+
+If you use an import statement in your AIDL, even from the same package, you
+need to add a path to `LOCAL_AIDL_INCLUDES`.  This path should be relative to
+the root of the Android tree.  For instance, a file IFoo.aidl defining
+com.example.IFoo might sit in a folder hierarchy
+something/something-else/com/example/IFoo.aidl.  Then we would write:
+
+```
+LOCAL_AIDL_INCLUDES := something/something-else
+```
+
+Generated C++ ends up in nested namespaces corresponding to the interface’s
+package.  The generated header also corresponds to the interface package.  So
+com.example.IFoo becomes ::com::example::IFoo in header “com/example/IFoo.h”.
+
+Similar to how Java works, the suffix of the path to a .aidl file must match
+the package.  So if IFoo.aidl declares itself to be in package com.example, the
+folder structure (as given to `LOCAL_SRC_FILES`) must look like:
+`some/prefix/com/example/IFoo.aidl`.
+
+To generate code from .aidl files from another build target (e.g. another
+binary or java), just add a relative path to the .aidl files to
+`LOCAL_SRC_FILES`.  Remember that importing AIDL works the same, even for code
+in other directory hierarchies: add the include root path relative to the
+checkout root to `LOCAL_AIDL_INCLUDES`.
+
+### Type Mapping
+
+The following table summarizes the equivalent C++ types for common Java types
+and whether those types may be used as in/out/inout parameters in AIDL
+interfaces.
+
+| Java Type             | C++ Type            | inout | Notes                                                 |
+|-----------------------|---------------------|-------|-------------------------------------------------------|
+| boolean               | bool                | in    | "These 8 types are all considered primitives.         |
+| byte                  | int8\_t             | in    |                                                       |
+| char                  | char16\_t           | in    |                                                       |
+| int                   | int32\_t            | in    |                                                       |
+| long                  | int64\_t            | in    |                                                       |
+| float                 | float               | in    |                                                       |
+| double                | double              | in    |                                                       |
+| String                | String16            | in    | Supports null references.                             |
+| @utf8InCpp String     | std::string         | in    | @utf8InCpp causes UTF16 to UTF8 conversion in C++.    |
+| android.os.Parcelable | android::Parcelable | inout |                                                       |
+| T extends IBinder     | sp<T>               | in    |                                                       |
+| Arrays (T[])          | vector<T>           | inout | May contain only primitives, Strings and parcelables. |
+| List<String>          | vector<String16>    | inout |                                                       |
+| PersistableBundle     | PersistableBundle   | inout | binder/PersistableBundle.h                            |
+| List<IBinder>         | vector<sp<IBinder>> | inout |                                                       |
+| FileDescriptor        | unique_fd           | inout | android-base/unique_fd.h from libbase                 |
+
+Note that java.util.Map and java.utils.List are not good candidates for cross
+language communication because they may contain arbitrary types on the Java
+side.  For instance, Map is cast to Map<String,Object> and then the object
+values dynamically inspected and serialized as type/value pairs.  Support
+exists for sending arbitrary Java serializables, Android Bundles, etc.
+
+Note that annotations may be placed at the interface level, as well as on a
+type by type basis.  Interface level annotations will be applied
+opportunistically and be overridden by per type annotations.  For instance, an
+interface marked @nullable will still not allow null int parameters.
+
+### Implementing a generated interface
+
+Given an interface declaration like:
+
+```
+package foo;
+
+import bar.IAnotherInterface;
+
+interface IFoo {
+  IAnotherInterface DoSomething(int count, out List<String> output);
+}
+```
+
+`aidl-cpp` will generate a C++ interface:
+
+```
+namespace foo {
+
+// Some headers have been omitted for clarity.
+#include <android/String16.h>
+#include <cstdint>
+#include <vector>
+#include <bar/IAnotherInterface.h>
+
+// Some class members have been omitted for clarity.
+class IFoo : public android::IInterface {
+ public:
+  virtual android::binder::Status DoSomething(
+      int32_t count,
+      std::vector<android::String16>* output,
+      android::sp<bar::IAnotherInterface>* returned_value) = 0;
+};
+```
+
+Note that `aidl-cpp` will import headers for types used in the interface.  For
+imported types (e.g. parcelables and interfaces), it will import a header
+corresponding to the package/class name of the import.  For instance,
+`import bar.IAnotherInterface` causes aidl-cpp to generate
+`#include <bar/IAnotherInterface.h>`.
+
+When writing a service that implements this interface, write:
+
+```
+#include "foo/BnFoo.h"
+
+namespace unrelated_namespace {
+
+class MyFoo : public foo::BnFoo {
+ public:
+  android::binder::Status DoSomething(
+      int32_t count,
+      std::vector<android::String16>* output,
+      android::sp<bar::IAnotherInterface>* returned_value) override {
+    for (int32_t i = 0; i < count; ++i) {
+      output->push_back(String16("..."));
+    }
+    *returned_value = new InstanceOfAnotherInterface;
+    return Status::ok();
+  }
+};  // class MyFoo
+
+}  // namespace unrelated_namespace
+```
+
+Note that the output values, `output` and `returned_value` are passed by
+pointer, and that this pointer is always valid.
+
+#### Dependencies
+
+The generated C++ code will use symbols from libbinder as well as libutils.
+AIDL files using the FileDescriptor type will also explicitly require
+libnativehelper, although this is likely a transitive dependency of the other
+two, and should be included automatically within the Android build tree
+regardless.
+
+### C++ Parcelables
+
+In Java, a parcelable should extend android.os.Parcelable and provide a static
+final CREATOR field that acts as a factory for new instances/arrays of
+instances of the parcelable.  In addition, in order to be used as an out
+parameter, a parcelable class must define a readFromParcel method.
+
+In C++, parcelables must implement android::Parcelable from binder/Parcelable.h
+in libbinder.  Parcelables must define a constructor that takes no arguments.
+In order to be used in arrays, a parcelable must implement a copy or move
+constructor (called implicitly in vector).
+
+The C++ generator needs to know what header defines the C++ parcelable.  It
+learns this from the `cpp_header` directive shown below.  The generator takes
+this string and uses it as the literal include statement in generated code.
+The idea here is that you generate your code once, link it into a library along
+with parcelable implementations, and export appropriate header paths.  This
+header include must make sense in the context of the Android.mk that compiles
+this generated code.
+
+```
+// ExampleParcelable.aidl
+package com.example.android;
+
+// Native types must be aliased at their declaration in the appropriate .aidl
+// file.  This allows multiple interfaces to use a parcelable and its C++
+// equivalent without duplicating the mapping between the C++ and Java types.
+// Generator will assume bar/foo.h declares class
+// com::example::android::ExampleParcelable
+parcelable ExampleParcelable cpp_header "bar/foo.h";
+```
+
+### Null Reference Handling
+
+The aidl generator for both C++ and Java languages has been expanded to
+understand nullable annotations.
+
+Given an interface definition like:
+
+```
+interface IExample {
+  void ReadStrings(String neverNull, in @nullable String maybeNull);
+};
+```
+
+the generated C++ header code looks like:
+
+```
+class IExample {
+  android::binder::Status ReadStrings(
+      const android::String16& in_neverNull,
+      const std::unique_ptr<android::String16>& in_maybeNull);
+};
+```
+
+Note that by default, the generated C++ passes a const reference to the value
+of a parameter and rejects null references with a NullPointerException sent
+back the caller.  Parameters marked with @nullable are passed by pointer,
+allowing native services to explicitly control whether they allow method
+overloading via null parameters.  Java stubs and proxies currently do nothing
+with the @nullable annotation.
+
+Consider an AIDL type `in @nullable List<String> bar`.  This type
+indicates that the remote caller may pass in a list of strings, and that both
+the list and any string in the list may be null.  This type will map to a C++
+type `unique_ptr<vector<unique_ptr<String16>>>* bar`.  In this case:
+
+  - `bar` is never null
+  - `*bar` might be null
+  - `(*bar)->empty()` could be true
+  - `(**bar)[0]` could be null (and so on)
+
+### Exception Reporting
+
+C++ methods generated by the aidl generator return `android::binder::Status`
+objects, rather than `android::status_t`.  This Status object allows generated
+C++ code to send and receive exceptions (an exception type and a String16 error
+message) since we do not use real exceptions in C++.  More background on Status
+objects can be found here.
+
+For legacy support and migration ease, the Status object includes a mechanism
+to report a `android::status_t`.  However, that return code is interpreted by a
+different code path and does not include a helpful String message.
+
+For situations where your native service needs to throw an error code specific
+to the service, use `Status::fromServiceSpecificError()`.  This kind of
+exception comes with a helpful message and an integer error code.  Make your
+error codes consistent across services by using interface constants (see
+below).
diff --git a/aidl/docs/constants.md b/aidl/docs/constants.md
new file mode 100644
index 0000000..55fbd97
--- /dev/null
+++ b/aidl/docs/constants.md
@@ -0,0 +1,35 @@
+# Defining constants as part of an interface
+
+AIDL has been enhanced to support defining integer and string constants
+as part of an interface.
+
+## Integer constants
+
+```
+interface IMyInterface {
+    const int CONST_A = 1;
+    const int CONST_B = 2;
+    const int CONST_C = 3;
+    ...
+}
+```
+
+These map to appropriate 32 bit integer class constants in Java and C++ (e.g.
+`IMyInterface.CONST_A` and `IMyInterface::CONST_A` respectively).
+
+## String constants
+
+```
+interface IMyInterface {
+    const String CONST_A = "foo";
+    const String CONST_B = "bar";
+    ...
+}
+```
+
+These map to class level String constants in Java, and static getter
+functions that return a const android::String16& in C++.
+
+The constants are limited to contain printable ASCII characters < 0x10
+and without backspaces (i.e. no '\' character).
+
diff --git a/aidl/docs/making-changes.md b/aidl/docs/making-changes.md
new file mode 100644
index 0000000..ac84b86
--- /dev/null
+++ b/aidl/docs/making-changes.md
@@ -0,0 +1,21 @@
+# Making changes
+
+## Coding style
+
+This project was originally written in C, in the Android platform style.
+It has been substantially re-written in C++, in the Google C++ style.
+
+This style
+[is summarized here](https://google.github.io/styleguide/cppguide.html).
+
+When in doubt, clang-format -style=google is a good reference.
+
+## Testing
+
+This codebase has both integration and unittests, all of which are expected to
+consistently pass against a device/emulator:
+
+```
+$ ./runtests.sh && echo "All tests pass"
+
+```
diff --git a/aidl/generate_cpp.cpp b/aidl/generate_cpp.cpp
new file mode 100644
index 0000000..41e9fb4
--- /dev/null
+++ b/aidl/generate_cpp.cpp
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "generate_cpp.h"
+
+#include <cctype>
+#include <cstring>
+#include <memory>
+#include <random>
+#include <set>
+#include <string>
+
+#include <android-base/stringprintf.h>
+
+#include "aidl_language.h"
+#include "ast_cpp.h"
+#include "code_writer.h"
+#include "logging.h"
+#include "os.h"
+
+using android::base::StringPrintf;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+using std::set;
+
+namespace android {
+namespace aidl {
+namespace cpp {
+namespace internals {
+namespace {
+
+const char kAndroidStatusVarName[] = "_aidl_ret_status";
+const char kCodeVarName[] = "_aidl_code";
+const char kFlagsVarName[] = "_aidl_flags";
+const char kDataVarName[] = "_aidl_data";
+const char kErrorLabel[] = "_aidl_error";
+const char kImplVarName[] = "_aidl_impl";
+const char kReplyVarName[] = "_aidl_reply";
+const char kReturnVarName[] = "_aidl_return";
+const char kStatusVarName[] = "_aidl_status";
+const char kAndroidParcelLiteral[] = "::android::Parcel";
+const char kAndroidStatusLiteral[] = "::android::status_t";
+const char kAndroidStatusOk[] = "::android::OK";
+const char kBinderStatusLiteral[] = "::android::binder::Status";
+const char kIBinderHeader[] = "binder/IBinder.h";
+const char kIInterfaceHeader[] = "binder/IInterface.h";
+const char kParcelHeader[] = "binder/Parcel.h";
+const char kStatusHeader[] = "binder/Status.h";
+const char kString16Header[] = "utils/String16.h";
+const char kStrongPointerHeader[] = "utils/StrongPointer.h";
+
+unique_ptr<AstNode> BreakOnStatusNotOk() {
+  IfStatement* ret = new IfStatement(new Comparison(
+      new LiteralExpression(kAndroidStatusVarName), "!=",
+      new LiteralExpression(kAndroidStatusOk)));
+  ret->OnTrue()->AddLiteral("break");
+  return unique_ptr<AstNode>(ret);
+}
+
+unique_ptr<AstNode> GotoErrorOnBadStatus() {
+  IfStatement* ret = new IfStatement(new Comparison(
+      new LiteralExpression(kAndroidStatusVarName), "!=",
+      new LiteralExpression(kAndroidStatusOk)));
+  ret->OnTrue()->AddLiteral(StringPrintf("goto %s", kErrorLabel));
+  return unique_ptr<AstNode>(ret);
+}
+
+
+unique_ptr<AstNode> ReturnOnStatusNotOk() {
+  IfStatement* ret = new IfStatement(new Comparison(
+      new LiteralExpression(kAndroidStatusVarName), "!=",
+      new LiteralExpression(kAndroidStatusOk)));
+  ret->OnTrue()->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
+  return unique_ptr<AstNode>(ret);
+}
+
+string UpperCase(const std::string& s) {
+  string result = s;
+  for (char& c : result)
+    c = toupper(c);
+  return result;
+}
+
+string BuildVarName(const AidlArgument& a) {
+  string prefix = "out_";
+  if (a.GetDirection() & AidlArgument::IN_DIR) {
+    prefix = "in_";
+  }
+  return prefix + a.GetName();
+}
+
+ArgList BuildArgList(const TypeNamespace& types,
+                     const AidlMethod& method,
+                     bool for_declaration) {
+  // Build up the argument list for the server method call.
+  vector<string> method_arguments;
+  for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
+    string literal;
+    if (for_declaration) {
+      // Method declarations need types, pointers to out params, and variable
+      // names that match the .aidl specification.
+      const Type* type = a->GetType().GetLanguageType<Type>();
+
+      literal = type->CppType();
+
+      if (a->IsOut()) {
+        literal = literal + "*";
+      } else {
+        // We pass in parameters that are not primitives by const reference.
+        // Arrays of primitives are not primitives.
+        if (!type->IsCppPrimitive() || a->GetType().IsArray()) {
+          literal = "const " + literal + "&";
+        }
+      }
+
+      literal += " " + a->GetName();
+    } else {
+      if (a->IsOut()) { literal = "&"; }
+      literal += BuildVarName(*a);
+    }
+    method_arguments.push_back(literal);
+  }
+
+  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().c_str(),
+          kReturnVarName);
+    } else {
+      literal = string{"&"} + kReturnVarName;
+    }
+    method_arguments.push_back(literal);
+  }
+
+  return ArgList(method_arguments);
+}
+
+unique_ptr<Declaration> BuildMethodDecl(const AidlMethod& method,
+                                        const TypeNamespace& types,
+                                        bool for_interface) {
+  uint32_t modifiers = 0;
+  if (for_interface) {
+    modifiers |= MethodDecl::IS_VIRTUAL;
+    modifiers |= MethodDecl::IS_PURE_VIRTUAL;
+  } else {
+    modifiers |= MethodDecl::IS_OVERRIDE;
+  }
+
+  return unique_ptr<Declaration>{
+      new MethodDecl{kBinderStatusLiteral,
+                     method.GetName(),
+                     BuildArgList(types, method, true /* for method decl */),
+                     modifiers}};
+}
+
+unique_ptr<CppNamespace> NestInNamespaces(
+    vector<unique_ptr<Declaration>> decls,
+    const vector<string>& package) {
+  if (package.empty()) {
+    // We should also be checking this before we get this far, but do it again
+    // for the sake of unit tests and meaningful errors.
+    LOG(FATAL) << "C++ generation requires a package declaration "
+                  "for namespacing";
+  }
+  auto it = package.crbegin();  // Iterate over the namespaces inner to outer
+  unique_ptr<CppNamespace> inner{new CppNamespace{*it, std::move(decls)}};
+  ++it;
+  for (; it != package.crend(); ++it) {
+    inner.reset(new CppNamespace{*it, std::move(inner)});
+  }
+  return inner;
+}
+
+unique_ptr<CppNamespace> NestInNamespaces(unique_ptr<Declaration> decl,
+                                          const vector<string>& package) {
+  vector<unique_ptr<Declaration>> decls;
+  decls.push_back(std::move(decl));
+  return NestInNamespaces(std::move(decls), package);
+}
+
+bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a,
+                          StatementBlock* b) {
+  const Type* cpp_type = a.GetType().GetLanguageType<Type>();
+  if (!cpp_type) { return false; }
+
+  string type = cpp_type->CppType();
+
+  b->AddLiteral(type + " " + BuildVarName(a));
+  return true;
+}
+
+string ClassName(const AidlInterface& interface, ClassNames type) {
+  string c_name = interface.GetName();
+
+  if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
+    c_name = c_name.substr(1);
+
+  switch (type) {
+    case ClassNames::CLIENT:
+      c_name = "Bp" + c_name;
+      break;
+    case ClassNames::SERVER:
+      c_name = "Bn" + c_name;
+      break;
+    case ClassNames::INTERFACE:
+      c_name = "I" + c_name;
+      break;
+    case ClassNames::BASE:
+      break;
+  }
+  return c_name;
+}
+
+string BuildHeaderGuard(const AidlInterface& interface,
+                        ClassNames header_type) {
+  string class_name = ClassName(interface, header_type);
+  for (size_t i = 1; i < class_name.size(); ++i) {
+    if (isupper(class_name[i])) {
+      class_name.insert(i, "_");
+      ++i;
+    }
+  }
+  string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_",
+                            interface.GetPackage().c_str(),
+                            class_name.c_str());
+  for (char& c : ret) {
+    if (c == '.') {
+      c = '_';
+    }
+    c = toupper(c);
+  }
+  return ret;
+}
+
+unique_ptr<Declaration> DefineClientTransaction(const TypeNamespace& types,
+                                                const AidlInterface& interface,
+                                                const AidlMethod& method) {
+  const string i_name = ClassName(interface, ClassNames::INTERFACE);
+  const string bp_name = ClassName(interface, ClassNames::CLIENT);
+  unique_ptr<MethodImpl> ret{new MethodImpl{
+      kBinderStatusLiteral, bp_name, method.GetName(),
+      ArgList{BuildArgList(types, method, true /* for method decl */)}}};
+  StatementBlock* b = ret->GetStatementBlock();
+
+  // Declare parcels to hold our query and the response.
+  b->AddLiteral(StringPrintf("%s %s", kAndroidParcelLiteral, kDataVarName));
+  // Even if we're oneway, the transact method still takes a parcel.
+  b->AddLiteral(StringPrintf("%s %s", kAndroidParcelLiteral, kReplyVarName));
+
+  // Declare the status_t variable we need for error handling.
+  b->AddLiteral(StringPrintf("%s %s = %s", kAndroidStatusLiteral,
+                             kAndroidStatusVarName,
+                             kAndroidStatusOk));
+  // We unconditionally return a Status object.
+  b->AddLiteral(StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName));
+
+  // Add the name of the interface we're hoping to call.
+  b->AddStatement(new Assignment(
+      kAndroidStatusVarName,
+      new MethodCall(StringPrintf("%s.writeInterfaceToken",
+                                  kDataVarName),
+                     "getInterfaceDescriptor()")));
+  b->AddStatement(GotoErrorOnBadStatus());
+
+  for (const auto& a: method.GetArguments()) {
+    const Type* type = a->GetType().GetLanguageType<Type>();
+    string var_name = ((a->IsOut()) ? "*" : "") + a->GetName();
+    var_name = type->WriteCast(var_name);
+
+    if (a->IsIn()) {
+      // Serialization looks roughly like:
+      //     _aidl_ret_status = _aidl_data.WriteInt32(in_param_name);
+      //     if (_aidl_ret_status != ::android::OK) { goto error; }
+      const string& method = type->WriteToParcelMethod();
+      b->AddStatement(new Assignment(
+          kAndroidStatusVarName,
+          new MethodCall(StringPrintf("%s.%s", kDataVarName, method.c_str()),
+                         ArgList(var_name))));
+      b->AddStatement(GotoErrorOnBadStatus());
+    } else if (a->IsOut() && a->GetType().IsArray()) {
+      // Special case, the length of the out array is written into the parcel.
+      //     _aidl_ret_status = _aidl_data.writeVectorSize(&out_param_name);
+      //     if (_aidl_ret_status != ::android::OK) { goto error; }
+      b->AddStatement(new Assignment(
+          kAndroidStatusVarName,
+          new MethodCall(StringPrintf("%s.writeVectorSize", kDataVarName),
+                         ArgList(var_name))));
+      b->AddStatement(GotoErrorOnBadStatus());
+    }
+  }
+
+  // Invoke the transaction on the remote binder and confirm status.
+  string transaction_code = StringPrintf(
+      "%s::%s", i_name.c_str(), UpperCase(method.GetName()).c_str());
+
+  vector<string> args = {transaction_code, kDataVarName,
+                         StringPrintf("&%s", kReplyVarName)};
+
+  if (interface.IsOneway() || method.IsOneway()) {
+    args.push_back("::android::IBinder::FLAG_ONEWAY");
+  }
+
+  b->AddStatement(new Assignment(
+      kAndroidStatusVarName,
+      new MethodCall("remote()->transact",
+                     ArgList(args))));
+  b->AddStatement(GotoErrorOnBadStatus());
+
+  if (!interface.IsOneway() && !method.IsOneway()) {
+    // Strip off the exception header and fail if we see a remote exception.
+    // _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+    // if (_aidl_ret_status != ::android::OK) { goto error; }
+    // if (!_aidl_status.isOk()) { return _aidl_ret_status; }
+    b->AddStatement(new Assignment(
+        kAndroidStatusVarName,
+        StringPrintf("%s.readFromParcel(%s)", kStatusVarName, kReplyVarName)));
+    b->AddStatement(GotoErrorOnBadStatus());
+    IfStatement* exception_check = new IfStatement(
+        new LiteralExpression(StringPrintf("!%s.isOk()", kStatusVarName)));
+    b->AddStatement(exception_check);
+    exception_check->OnTrue()->AddLiteral(
+        StringPrintf("return %s", kStatusVarName));
+  }
+
+  // Type checking should guarantee that nothing below emits code until "return
+  // 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 = method.GetType().GetLanguageType<Type>();
+  if (return_type != types.VoidType()) {
+    const string& method_call = return_type->ReadFromParcelMethod();
+    b->AddStatement(new Assignment(
+        kAndroidStatusVarName,
+        new MethodCall(StringPrintf("%s.%s", kReplyVarName,
+                                    method_call.c_str()),
+                       ArgList(kReturnVarName))));
+    b->AddStatement(GotoErrorOnBadStatus());
+  }
+
+  for (const AidlArgument* a : method.GetOutArguments()) {
+    // Deserialization looks roughly like:
+    //     _aidl_ret_status = _aidl_reply.ReadInt32(out_param_name);
+    //     if (_aidl_status != ::android::OK) { goto _aidl_error; }
+    string method =
+      a->GetType().GetLanguageType<Type>()->ReadFromParcelMethod();
+
+    b->AddStatement(new Assignment(
+        kAndroidStatusVarName,
+        new MethodCall(StringPrintf("%s.%s", kReplyVarName,
+                                    method.c_str()),
+                       ArgList(a->GetName()))));
+    b->AddStatement(GotoErrorOnBadStatus());
+  }
+
+  // If we've gotten to here, one of two things is true:
+  //   1) We've read some bad status_t
+  //   2) We've only read status_t == OK and there was no exception in the
+  //      response.
+  // In both cases, we're free to set Status from the status_t and return.
+  b->AddLiteral(StringPrintf("%s:\n", kErrorLabel), false /* no semicolon */);
+  b->AddLiteral(
+      StringPrintf("%s.setFromStatusT(%s)", kStatusVarName,
+                   kAndroidStatusVarName));
+  b->AddLiteral(StringPrintf("return %s", kStatusVarName));
+
+  return unique_ptr<Declaration>(ret.release());
+}
+
+}  // namespace
+
+unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
+                                       const AidlInterface& interface) {
+  vector<string> include_list = {
+      HeaderFile(interface, ClassNames::CLIENT, false),
+      kParcelHeader
+  };
+  vector<unique_ptr<Declaration>> file_decls;
+
+  // The constructor just passes the IBinder instance up to the super
+  // class.
+  const string i_name = ClassName(interface, ClassNames::INTERFACE);
+  file_decls.push_back(unique_ptr<Declaration>{new ConstructorImpl{
+      ClassName(interface, ClassNames::CLIENT),
+      ArgList{StringPrintf("const ::android::sp<::android::IBinder>& %s",
+                           kImplVarName)},
+      { "BpInterface<" + i_name + ">(" + kImplVarName + ")" }}});
+
+  // Clients define a method per transaction.
+  for (const auto& method : interface.GetMethods()) {
+    unique_ptr<Declaration> m = DefineClientTransaction(
+        types, interface, *method);
+    if (!m) { return nullptr; }
+    file_decls.push_back(std::move(m));
+  }
+  return unique_ptr<Document>{new CppSource{
+      include_list,
+      NestInNamespaces(std::move(file_decls), interface.GetSplitPackage())}};
+}
+
+namespace {
+
+bool HandleServerTransaction(const TypeNamespace& types,
+                             const AidlMethod& method,
+                             StatementBlock* b) {
+  // Declare all the parameters now.  In the common case, we expect no errors
+  // in serialization.
+  for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
+    if (!DeclareLocalVariable(types, *a, b)) { return false; }
+  }
+
+  // Declare a variable to hold the return value.
+  const Type* return_type = method.GetType().GetLanguageType<Type>();
+  if (return_type != types.VoidType()) {
+    b->AddLiteral(StringPrintf(
+        "%s %s", return_type->CppType().c_str(),
+        kReturnVarName));
+  }
+
+  // Check that the client is calling the correct interface.
+  IfStatement* interface_check = new IfStatement(
+      new MethodCall(StringPrintf("%s.checkInterface",
+                                  kDataVarName), "this"),
+      true /* invert the check */);
+  b->AddStatement(interface_check);
+  interface_check->OnTrue()->AddStatement(
+      new Assignment(kAndroidStatusVarName, "::android::BAD_TYPE"));
+  interface_check->OnTrue()->AddLiteral("break");
+
+  // Deserialize each "in" parameter to the transaction.
+  for (const auto& a: method.GetArguments()) {
+    // Deserialization looks roughly like:
+    //     _aidl_ret_status = _aidl_data.ReadInt32(&in_param_name);
+    //     if (_aidl_ret_status != ::android::OK) { break; }
+    const Type* type = a->GetType().GetLanguageType<Type>();
+    const string& readMethod = type->ReadFromParcelMethod();
+
+    if (a->IsIn()) {
+      b->AddStatement(new Assignment{
+          kAndroidStatusVarName,
+          new MethodCall{string(kDataVarName) + "." + readMethod,
+                         "&" + BuildVarName(*a)}});
+      b->AddStatement(BreakOnStatusNotOk());
+    } else if (a->IsOut() && a->GetType().IsArray()) {
+      // Special case, the length of the out array is written into the parcel.
+      //     _aidl_ret_status = _aidl_data.resizeOutVector(&out_param_name);
+      //     if (_aidl_ret_status != ::android::OK) { break; }
+      b->AddStatement(new Assignment{
+          kAndroidStatusVarName,
+          new MethodCall{string(kDataVarName) + ".resizeOutVector",
+                         "&" + BuildVarName(*a)}});
+      b->AddStatement(BreakOnStatusNotOk());
+    }
+  }
+
+  // Call the actual method.  This is implemented by the subclass.
+  vector<unique_ptr<AstNode>> status_args;
+  status_args.emplace_back(new MethodCall(
+          method.GetName(),
+          BuildArgList(types, method, false /* not for method decl */)));
+  b->AddStatement(new Statement(new MethodCall(
+      StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName),
+      ArgList(std::move(status_args)))));
+
+  // Write exceptions during transaction handling to parcel.
+  if (!method.IsOneway()) {
+    b->AddStatement(new Assignment(
+        kAndroidStatusVarName,
+        StringPrintf("%s.writeToParcel(%s)", kStatusVarName, kReplyVarName)));
+    b->AddStatement(BreakOnStatusNotOk());
+    IfStatement* exception_check = new IfStatement(
+        new LiteralExpression(StringPrintf("!%s.isOk()", kStatusVarName)));
+    b->AddStatement(exception_check);
+    exception_check->OnTrue()->AddLiteral("break");
+  }
+
+  // If we have a return value, write it first.
+  if (return_type != types.VoidType()) {
+    string writeMethod =
+        string(kReplyVarName) + "->" +
+        return_type->WriteToParcelMethod();
+    b->AddStatement(new Assignment{
+        kAndroidStatusVarName, new MethodCall{writeMethod,
+        ArgList{return_type->WriteCast(kReturnVarName)}}});
+    b->AddStatement(BreakOnStatusNotOk());
+  }
+
+  // Write each out parameter to the reply parcel.
+  for (const AidlArgument* a : method.GetOutArguments()) {
+    // Serialization looks roughly like:
+    //     _aidl_ret_status = data.WriteInt32(out_param_name);
+    //     if (_aidl_ret_status != ::android::OK) { break; }
+    const Type* type = a->GetType().GetLanguageType<Type>();
+    const string& writeMethod = type->WriteToParcelMethod();
+
+    b->AddStatement(new Assignment{
+        kAndroidStatusVarName,
+        new MethodCall{string(kReplyVarName) + "->" + writeMethod,
+                       type->WriteCast(BuildVarName(*a))}});
+    b->AddStatement(BreakOnStatusNotOk());
+  }
+
+  return true;
+}
+
+}  // namespace
+
+unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
+                                       const AidlInterface& interface) {
+  const string bn_name = ClassName(interface, ClassNames::SERVER);
+  vector<string> include_list{
+      HeaderFile(interface, ClassNames::SERVER, false),
+      kParcelHeader
+  };
+  unique_ptr<MethodImpl> on_transact{new MethodImpl{
+      kAndroidStatusLiteral, bn_name, "onTransact",
+      ArgList{{StringPrintf("uint32_t %s", kCodeVarName),
+               StringPrintf("const %s& %s", kAndroidParcelLiteral,
+                            kDataVarName),
+               StringPrintf("%s* %s", kAndroidParcelLiteral, kReplyVarName),
+               StringPrintf("uint32_t %s", kFlagsVarName)}}
+      }};
+
+  // Declare the status_t variable
+  on_transact->GetStatementBlock()->AddLiteral(
+      StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName,
+                   kAndroidStatusOk));
+
+  // Add the all important switch statement, but retain a pointer to it.
+  SwitchStatement* s = new SwitchStatement{kCodeVarName};
+  on_transact->GetStatementBlock()->AddStatement(s);
+
+  // The switch statement has a case statement for each transaction code.
+  for (const auto& method : interface.GetMethods()) {
+    StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName()));
+    if (!b) { return nullptr; }
+
+    if (!HandleServerTransaction(types, *method, b)) { return nullptr; }
+  }
+
+  // The switch statement has a default case which defers to the super class.
+  // The superclass handles a few pre-defined transactions.
+  StatementBlock* b = s->AddCase("");
+  b->AddLiteral(StringPrintf(
+                "%s = ::android::BBinder::onTransact(%s, %s, "
+                "%s, %s)", kAndroidStatusVarName, kCodeVarName,
+                kDataVarName, kReplyVarName, kFlagsVarName));
+
+  // If we saw a null reference, we can map that to an appropriate exception.
+  IfStatement* null_check = new IfStatement(
+      new LiteralExpression(string(kAndroidStatusVarName) +
+                            " == ::android::UNEXPECTED_NULL"));
+  on_transact->GetStatementBlock()->AddStatement(null_check);
+  null_check->OnTrue()->AddStatement(new Assignment(
+      kAndroidStatusVarName,
+      StringPrintf("%s::fromExceptionCode(%s::EX_NULL_POINTER)"
+                   ".writeToParcel(%s)",
+                   kBinderStatusLiteral, kBinderStatusLiteral,
+                   kReplyVarName)));
+
+  // Finally, the server's onTransact method just returns a status code.
+  on_transact->GetStatementBlock()->AddLiteral(
+      StringPrintf("return %s", kAndroidStatusVarName));
+
+  return unique_ptr<Document>{new CppSource{
+      include_list,
+      NestInNamespaces(std::move(on_transact), interface.GetSplitPackage())}};
+}
+
+unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& /* types */,
+                                          const AidlInterface& interface) {
+  vector<string> include_list{
+      HeaderFile(interface, ClassNames::INTERFACE, false),
+      HeaderFile(interface, ClassNames::CLIENT, false),
+  };
+
+  string fq_name = ClassName(interface, ClassNames::INTERFACE);
+  if (!interface.GetPackage().empty()) {
+    fq_name = interface.GetPackage() + "." + fq_name;
+  }
+
+  vector<unique_ptr<Declaration>> decls;
+
+  unique_ptr<MacroDecl> meta_if{new MacroDecl{
+      "IMPLEMENT_META_INTERFACE",
+      ArgList{vector<string>{ClassName(interface, ClassNames::BASE),
+                             '"' + fq_name + '"'}}}};
+  decls.push_back(std::move(meta_if));
+
+  for (const auto& constant: interface.GetStringConstants()) {
+    unique_ptr<MethodImpl> getter(new MethodImpl(
+        "const ::android::String16&",
+        ClassName(interface, ClassNames::INTERFACE),
+        constant->GetName(),
+        {}));
+    getter->GetStatementBlock()->AddLiteral(
+        StringPrintf("static const ::android::String16 value(%s)",
+                     constant->GetValue().c_str()));
+    getter->GetStatementBlock()->AddLiteral("return value");
+    decls.push_back(std::move(getter));
+  }
+
+  return unique_ptr<Document>{new CppSource{
+      include_list,
+      NestInNamespaces(std::move(decls), interface.GetSplitPackage())}};
+}
+
+unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
+                                       const AidlInterface& interface) {
+  const string i_name = ClassName(interface, ClassNames::INTERFACE);
+  const string bp_name = ClassName(interface, ClassNames::CLIENT);
+
+  unique_ptr<ConstructorDecl> constructor{new ConstructorDecl{
+      bp_name,
+      ArgList{StringPrintf("const ::android::sp<::android::IBinder>& %s",
+                           kImplVarName)},
+      ConstructorDecl::IS_EXPLICIT
+  }};
+  unique_ptr<ConstructorDecl> destructor{new ConstructorDecl{
+      "~" + bp_name,
+      ArgList{},
+      ConstructorDecl::IS_VIRTUAL | ConstructorDecl::IS_DEFAULT}};
+
+  vector<unique_ptr<Declaration>> publics;
+  publics.push_back(std::move(constructor));
+  publics.push_back(std::move(destructor));
+
+  for (const auto& method: interface.GetMethods()) {
+    publics.push_back(BuildMethodDecl(*method, types, false));
+  }
+
+  unique_ptr<ClassDecl> bp_class{
+      new ClassDecl{bp_name,
+                    "::android::BpInterface<" + i_name + ">",
+                    std::move(publics),
+                    {}
+      }};
+
+  return unique_ptr<Document>{new CppHeader{
+      BuildHeaderGuard(interface, ClassNames::CLIENT),
+      {kIBinderHeader,
+       kIInterfaceHeader,
+       "utils/Errors.h",
+       HeaderFile(interface, ClassNames::INTERFACE, false)},
+      NestInNamespaces(std::move(bp_class), interface.GetSplitPackage())}};
+}
+
+unique_ptr<Document> BuildServerHeader(const TypeNamespace& /* types */,
+                                       const AidlInterface& interface) {
+  const string i_name = ClassName(interface, ClassNames::INTERFACE);
+  const string bn_name = ClassName(interface, ClassNames::SERVER);
+
+  unique_ptr<Declaration> on_transact{new MethodDecl{
+      kAndroidStatusLiteral, "onTransact",
+      ArgList{{StringPrintf("uint32_t %s", kCodeVarName),
+               StringPrintf("const %s& %s", kAndroidParcelLiteral,
+                            kDataVarName),
+               StringPrintf("%s* %s", kAndroidParcelLiteral, kReplyVarName),
+               StringPrintf("uint32_t %s = 0", kFlagsVarName)}},
+      MethodDecl::IS_OVERRIDE
+  }};
+
+  std::vector<unique_ptr<Declaration>> publics;
+  publics.push_back(std::move(on_transact));
+
+  unique_ptr<ClassDecl> bn_class{
+      new ClassDecl{bn_name,
+                    "::android::BnInterface<" + i_name + ">",
+                    std::move(publics),
+                    {}
+      }};
+
+  return unique_ptr<Document>{new CppHeader{
+      BuildHeaderGuard(interface, ClassNames::SERVER),
+      {"binder/IInterface.h",
+       HeaderFile(interface, ClassNames::INTERFACE, false)},
+      NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}};
+}
+
+unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
+                                          const AidlInterface& interface) {
+  set<string> includes = { kIBinderHeader, kIInterfaceHeader,
+                           kStatusHeader, kStrongPointerHeader };
+
+  for (const auto& method : interface.GetMethods()) {
+    for (const auto& argument : method->GetArguments()) {
+      const Type* type = argument->GetType().GetLanguageType<Type>();
+      type->GetHeaders(&includes);
+    }
+
+    const Type* return_type = method->GetType().GetLanguageType<Type>();
+    return_type->GetHeaders(&includes);
+  }
+
+  unique_ptr<ClassDecl> if_class{
+      new ClassDecl{ClassName(interface, ClassNames::INTERFACE),
+                    "::android::IInterface"}};
+  if_class->AddPublic(unique_ptr<Declaration>{new MacroDecl{
+      "DECLARE_META_INTERFACE",
+      ArgList{vector<string>{ClassName(interface, ClassNames::BASE)}}}});
+
+  unique_ptr<Enum> constant_enum{new Enum{"", "int32_t"}};
+  for (const auto& constant : interface.GetIntConstants()) {
+    constant_enum->AddValue(
+        constant->GetName(), std::to_string(constant->GetValue()));
+  }
+  if (constant_enum->HasValues()) {
+    if_class->AddPublic(std::move(constant_enum));
+  }
+
+  if (!interface.GetStringConstants().empty()) {
+    includes.insert(kString16Header);
+  }
+  for (const auto& constant : interface.GetStringConstants()) {
+    unique_ptr<MethodDecl> getter(new MethodDecl(
+          "const ::android::String16&", constant->GetName(),
+          {}, MethodDecl::IS_STATIC));
+    if_class->AddPublic(std::move(getter));
+  }
+
+  if (!interface.GetMethods().empty()) {
+    unique_ptr<Enum> call_enum{new Enum{"Call"}};
+    for (const auto& method : interface.GetMethods()) {
+      // Each method gets an enum entry and pure virtual declaration.
+      if_class->AddPublic(BuildMethodDecl(*method, types, true));
+      call_enum->AddValue(
+          UpperCase(method->GetName()),
+          StringPrintf("::android::IBinder::FIRST_CALL_TRANSACTION + %d",
+                       method->GetId()));
+    }
+    if_class->AddPublic(std::move(call_enum));
+  }
+
+  return unique_ptr<Document>{new CppHeader{
+      BuildHeaderGuard(interface, ClassNames::INTERFACE),
+      vector<string>(includes.begin(), includes.end()),
+      NestInNamespaces(std::move(if_class), interface.GetSplitPackage())}};
+}
+
+bool WriteHeader(const CppOptions& options,
+                 const TypeNamespace& types,
+                 const AidlInterface& interface,
+                 const IoDelegate& io_delegate,
+                 ClassNames header_type) {
+  unique_ptr<Document> header;
+  switch (header_type) {
+    case ClassNames::INTERFACE:
+      header = BuildInterfaceHeader(types, interface);
+      break;
+    case ClassNames::CLIENT:
+      header = BuildClientHeader(types, interface);
+      break;
+    case ClassNames::SERVER:
+      header = BuildServerHeader(types, interface);
+      break;
+    default:
+      LOG(FATAL) << "aidl internal error";
+  }
+  if (!header) {
+    LOG(ERROR) << "aidl internal error: Failed to generate header.";
+    return false;
+  }
+
+  const string header_path = options.OutputHeaderDir() + OS_PATH_SEPARATOR +
+                             HeaderFile(interface, header_type);
+  unique_ptr<CodeWriter> code_writer(io_delegate.GetCodeWriter(header_path));
+  header->Write(code_writer.get());
+
+  const bool success = code_writer->Close();
+  if (!success) {
+    io_delegate.RemovePath(header_path);
+  }
+
+  return success;
+}
+
+}  // namespace internals
+
+using namespace internals;
+
+string HeaderFile(const AidlInterface& interface,
+                  ClassNames class_type,
+                  bool use_os_sep) {
+  string file_path = interface.GetPackage();
+  for (char& c: file_path) {
+    if (c == '.') {
+      c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
+    }
+  }
+  if (!file_path.empty()) {
+    file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
+  }
+  file_path += ClassName(interface, class_type);
+  file_path += ".h";
+
+  return file_path;
+}
+
+bool GenerateCpp(const CppOptions& options,
+                 const TypeNamespace& types,
+                 const AidlInterface& interface,
+                 const IoDelegate& io_delegate) {
+  auto interface_src = BuildInterfaceSource(types, interface);
+  auto client_src = BuildClientSource(types, interface);
+  auto server_src = BuildServerSource(types, interface);
+
+  if (!interface_src || !client_src || !server_src) {
+    return false;
+  }
+
+  if (!io_delegate.CreatedNestedDirs(options.OutputHeaderDir(),
+                                     interface.GetSplitPackage())) {
+    LOG(ERROR) << "Failed to create directory structure for headers.";
+    return false;
+  }
+
+  if (!WriteHeader(options, types, interface, io_delegate,
+                   ClassNames::INTERFACE) ||
+      !WriteHeader(options, types, interface, io_delegate,
+                   ClassNames::CLIENT) ||
+      !WriteHeader(options, types, interface, io_delegate,
+                   ClassNames::SERVER)) {
+    return false;
+  }
+
+  unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(
+      options.OutputCppFilePath());
+  interface_src->Write(writer.get());
+  client_src->Write(writer.get());
+  server_src->Write(writer.get());
+
+  const bool success = writer->Close();
+  if (!success) {
+    io_delegate.RemovePath(options.OutputCppFilePath());
+  }
+
+  return success;
+}
+
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/generate_cpp.h b/aidl/generate_cpp.h
new file mode 100644
index 0000000..1ffc681
--- /dev/null
+++ b/aidl/generate_cpp.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_GENERATE_CPP_H_
+#define AIDL_GENERATE_CPP_H_
+
+#include <memory>
+#include <string>
+
+#include "aidl_language.h"
+#include "ast_cpp.h"
+#include "options.h"
+#include "type_cpp.h"
+
+namespace android {
+namespace aidl {
+namespace cpp {
+
+bool GenerateCpp(const CppOptions& options,
+                 const cpp::TypeNamespace& types,
+                 const AidlInterface& parsed_doc,
+                 const IoDelegate& io_delegate);
+
+// These roughly correspond to the various class names in the C++ hierarchy:
+enum class ClassNames {
+  BASE,       // Foo (not a real class, but useful in some circumstances).
+  CLIENT,     // BpFoo
+  SERVER,     // BnFoo
+  INTERFACE,  // IFoo
+};
+
+// Generate the relative path to a header file.  If |use_os_sep| we'll use the
+// operating system specific path separator rather than C++'s expected '/' when
+// including headers.
+std::string HeaderFile(const AidlInterface& interface, ClassNames class_type,
+                       bool use_os_sep = true);
+
+namespace internals {
+std::unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
+                                            const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
+                                            const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
+                                               const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
+                                            const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildServerHeader(const TypeNamespace& types,
+                                            const AidlInterface& parsed_doc);
+std::unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
+                                               const AidlInterface& parsed_doc);
+}
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
+
+#endif // AIDL_GENERATE_CPP_H_
diff --git a/aidl/generate_cpp_unittest.cpp b/aidl/generate_cpp_unittest.cpp
new file mode 100644
index 0000000..50bfd9c
--- /dev/null
+++ b/aidl/generate_cpp_unittest.cpp
@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "aidl.h"
+#include "aidl_language.h"
+#include "ast_cpp.h"
+#include "code_writer.h"
+#include "generate_cpp.h"
+#include "os.h"
+#include "tests/fake_io_delegate.h"
+#include "tests/test_util.h"
+#include "type_cpp.h"
+
+using ::android::aidl::test::FakeIoDelegate;
+using ::android::base::StringPrintf;
+using std::string;
+using std::unique_ptr;
+
+namespace android {
+namespace aidl {
+namespace cpp {
+namespace {
+
+const string kComplexTypeInterfaceAIDL =
+R"(package android.os;
+import foo.IFooType;
+interface IComplexTypeInterface {
+  const int MY_CONSTANT = 3;
+  int[] Send(in @nullable int[] goes_in, inout double[] goes_in_and_out, out boolean[] goes_out);
+  oneway void Piff(int times);
+  IFooType TakesABinder(IFooType f);
+  @nullable IFooType NullableBinder();
+  List<String> StringListMethod(in java.util.List<String> input, out List<String> output);
+  List<IBinder> BinderListMethod(in java.util.List<IBinder> input, out List<IBinder> output);
+  FileDescriptor TakesAFileDescriptor(in FileDescriptor f);
+  FileDescriptor[] TakesAFileDescriptorArray(in FileDescriptor[] f);
+})";
+
+const char kExpectedComplexTypeClientHeaderOutput[] =
+R"(#ifndef AIDL_GENERATED_ANDROID_OS_BP_COMPLEX_TYPE_INTERFACE_H_
+#define AIDL_GENERATED_ANDROID_OS_BP_COMPLEX_TYPE_INTERFACE_H_
+
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <utils/Errors.h>
+#include <android/os/IComplexTypeInterface.h>
+
+namespace android {
+
+namespace os {
+
+class BpComplexTypeInterface : public ::android::BpInterface<IComplexTypeInterface> {
+public:
+explicit BpComplexTypeInterface(const ::android::sp<::android::IBinder>& _aidl_impl);
+virtual ~BpComplexTypeInterface() = default;
+::android::binder::Status Send(const ::std::unique_ptr<::std::vector<int32_t>>& goes_in, ::std::vector<double>* goes_in_and_out, ::std::vector<bool>* goes_out, ::std::vector<int32_t>* _aidl_return) override;
+::android::binder::Status Piff(int32_t times) override;
+::android::binder::Status TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) override;
+::android::binder::Status NullableBinder(::android::sp<::foo::IFooType>* _aidl_return) override;
+::android::binder::Status StringListMethod(const ::std::vector<::android::String16>& input, ::std::vector<::android::String16>* output, ::std::vector<::android::String16>* _aidl_return) override;
+::android::binder::Status BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>& input, ::std::vector<::android::sp<::android::IBinder>>* output, ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) override;
+::android::binder::Status TakesAFileDescriptor(const ::android::base::unique_fd& f, ::android::base::unique_fd* _aidl_return) override;
+::android::binder::Status TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>& f, ::std::vector<::android::base::unique_fd>* _aidl_return) override;
+};  // class BpComplexTypeInterface
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // AIDL_GENERATED_ANDROID_OS_BP_COMPLEX_TYPE_INTERFACE_H_
+)";
+
+const char kExpectedComplexTypeClientSourceOutput[] =
+R"(#include <android/os/BpComplexTypeInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+BpComplexTypeInterface::BpComplexTypeInterface(const ::android::sp<::android::IBinder>& _aidl_impl)
+    : BpInterface<IComplexTypeInterface>(_aidl_impl){
+}
+
+::android::binder::Status BpComplexTypeInterface::Send(const ::std::unique_ptr<::std::vector<int32_t>>& goes_in, ::std::vector<double>* goes_in_and_out, ::std::vector<bool>* goes_out, ::std::vector<int32_t>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeInt32Vector(goes_in);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeDoubleVector(*goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeVectorSize(*goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::SEND, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readInt32Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readDoubleVector(goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readBoolVector(goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::Piff(int32_t times) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeInt32(times);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::PIFF, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeStrongBinder(::foo::IFooType::asBinder(f));
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESABINDER, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readStrongBinder(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::NullableBinder(::android::sp<::foo::IFooType>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::NULLABLEBINDER, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::StringListMethod(const ::std::vector<::android::String16>& input, ::std::vector<::android::String16>* output, ::std::vector<::android::String16>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeString16Vector(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::STRINGLISTMETHOD, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readString16Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readString16Vector(output);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>& input, ::std::vector<::android::sp<::android::IBinder>>* output, ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeStrongBinderVector(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::BINDERLISTMETHOD, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readStrongBinderVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_reply.readStrongBinderVector(output);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::TakesAFileDescriptor(const ::android::base::unique_fd& f, ::android::base::unique_fd* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeUniqueFileDescriptor(f);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESAFILEDESCRIPTOR, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readUniqueFileDescriptor(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpComplexTypeInterface::TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>& f, ::std::vector<::android::base::unique_fd>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeUniqueFileDescriptorVector(f);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESAFILEDESCRIPTORARRAY, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readUniqueFileDescriptorVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+}  // namespace os
+
+}  // namespace android
+)";
+
+const char kExpectedComplexTypeServerHeaderOutput[] =
+R"(#ifndef AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_
+#define AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_
+
+#include <binder/IInterface.h>
+#include <android/os/IComplexTypeInterface.h>
+
+namespace android {
+
+namespace os {
+
+class BnComplexTypeInterface : public ::android::BnInterface<IComplexTypeInterface> {
+public:
+::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags = 0) override;
+};  // class BnComplexTypeInterface
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_
+)";
+
+const char kExpectedComplexTypeServerSourceOutput[] =
+R"(#include <android/os/BnComplexTypeInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+::android::status_t BnComplexTypeInterface::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
+::android::status_t _aidl_ret_status = ::android::OK;
+switch (_aidl_code) {
+case Call::SEND:
+{
+::std::unique_ptr<::std::vector<int32_t>> in_goes_in;
+::std::vector<double> in_goes_in_and_out;
+::std::vector<bool> out_goes_out;
+::std::vector<int32_t> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readInt32Vector(&in_goes_in);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_data.readDoubleVector(&in_goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_data.resizeOutVector(&out_goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(Send(in_goes_in, &in_goes_in_and_out, &out_goes_out, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeInt32Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeDoubleVector(in_goes_in_and_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeBoolVector(out_goes_out);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::PIFF:
+{
+int32_t in_times;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readInt32(&in_times);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(Piff(in_times));
+}
+break;
+case Call::TAKESABINDER:
+{
+::android::sp<::foo::IFooType> in_f;
+::android::sp<::foo::IFooType> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readStrongBinder(&in_f);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(TakesABinder(in_f, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinder(::foo::IFooType::asBinder(_aidl_return));
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::NULLABLEBINDER:
+{
+::android::sp<::foo::IFooType> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+::android::binder::Status _aidl_status(NullableBinder(&_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinder(::foo::IFooType::asBinder(_aidl_return));
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::STRINGLISTMETHOD:
+{
+::std::vector<::android::String16> in_input;
+::std::vector<::android::String16> out_output;
+::std::vector<::android::String16> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readString16Vector(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(StringListMethod(in_input, &out_output, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeString16Vector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeString16Vector(out_output);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::BINDERLISTMETHOD:
+{
+::std::vector<::android::sp<::android::IBinder>> in_input;
+::std::vector<::android::sp<::android::IBinder>> out_output;
+::std::vector<::android::sp<::android::IBinder>> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readStrongBinderVector(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(BinderListMethod(in_input, &out_output, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinderVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeStrongBinderVector(out_output);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::TAKESAFILEDESCRIPTOR:
+{
+::android::base::unique_fd in_f;
+::android::base::unique_fd _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readUniqueFileDescriptor(&in_f);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(TakesAFileDescriptor(in_f, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeUniqueFileDescriptor(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::TAKESAFILEDESCRIPTORARRAY:
+{
+::std::vector<::android::base::unique_fd> in_f;
+::std::vector<::android::base::unique_fd> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readUniqueFileDescriptorVector(&in_f);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(TakesAFileDescriptorArray(in_f, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeUniqueFileDescriptorVector(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+default:
+{
+_aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
+}
+break;
+}
+if (_aidl_ret_status == ::android::UNEXPECTED_NULL) {
+_aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply);
+}
+return _aidl_ret_status;
+}
+
+}  // namespace os
+
+}  // namespace android
+)";
+
+const char kExpectedComplexTypeInterfaceHeaderOutput[] =
+R"(#ifndef AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_
+#define AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_
+
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <binder/Status.h>
+#include <cstdint>
+#include <foo/IFooType.h>
+#include <memory>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <vector>
+
+namespace android {
+
+namespace os {
+
+class IComplexTypeInterface : public ::android::IInterface {
+public:
+DECLARE_META_INTERFACE(ComplexTypeInterface)
+enum  : int32_t {
+  MY_CONSTANT = 3,
+};
+virtual ::android::binder::Status Send(const ::std::unique_ptr<::std::vector<int32_t>>& goes_in, ::std::vector<double>* goes_in_and_out, ::std::vector<bool>* goes_out, ::std::vector<int32_t>* _aidl_return) = 0;
+virtual ::android::binder::Status Piff(int32_t times) = 0;
+virtual ::android::binder::Status TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) = 0;
+virtual ::android::binder::Status NullableBinder(::android::sp<::foo::IFooType>* _aidl_return) = 0;
+virtual ::android::binder::Status StringListMethod(const ::std::vector<::android::String16>& input, ::std::vector<::android::String16>* output, ::std::vector<::android::String16>* _aidl_return) = 0;
+virtual ::android::binder::Status BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>& input, ::std::vector<::android::sp<::android::IBinder>>* output, ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) = 0;
+virtual ::android::binder::Status TakesAFileDescriptor(const ::android::base::unique_fd& f, ::android::base::unique_fd* _aidl_return) = 0;
+virtual ::android::binder::Status TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>& f, ::std::vector<::android::base::unique_fd>* _aidl_return) = 0;
+enum Call {
+  SEND = ::android::IBinder::FIRST_CALL_TRANSACTION + 0,
+  PIFF = ::android::IBinder::FIRST_CALL_TRANSACTION + 1,
+  TAKESABINDER = ::android::IBinder::FIRST_CALL_TRANSACTION + 2,
+  NULLABLEBINDER = ::android::IBinder::FIRST_CALL_TRANSACTION + 3,
+  STRINGLISTMETHOD = ::android::IBinder::FIRST_CALL_TRANSACTION + 4,
+  BINDERLISTMETHOD = ::android::IBinder::FIRST_CALL_TRANSACTION + 5,
+  TAKESAFILEDESCRIPTOR = ::android::IBinder::FIRST_CALL_TRANSACTION + 6,
+  TAKESAFILEDESCRIPTORARRAY = ::android::IBinder::FIRST_CALL_TRANSACTION + 7,
+};
+};  // class IComplexTypeInterface
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_
+)";
+
+const char kExpectedComplexTypeInterfaceSourceOutput[] =
+R"(#include <android/os/IComplexTypeInterface.h>
+#include <android/os/BpComplexTypeInterface.h>
+
+namespace android {
+
+namespace os {
+
+IMPLEMENT_META_INTERFACE(ComplexTypeInterface, "android.os.IComplexTypeInterface")
+
+}  // namespace os
+
+}  // namespace android
+)";
+
+}  // namespace
+
+class ASTTest : public ::testing::Test {
+ protected:
+  ASTTest(string file_path, string file_contents)
+      : file_path_(file_path),
+        file_contents_(file_contents) {
+    types_.Init();
+  }
+
+  unique_ptr<AidlInterface> Parse() {
+    io_delegate_.SetFileContents(file_path_, file_contents_);
+
+    unique_ptr<AidlInterface> ret;
+    std::vector<std::unique_ptr<AidlImport>> imports;
+    AidlError err = ::android::aidl::internals::load_and_validate_aidl(
+        {},  // no preprocessed files
+        {"."},
+        file_path_,
+        io_delegate_,
+        &types_,
+        &ret,
+        &imports);
+
+    if (err != AidlError::OK)
+      return nullptr;
+
+    return ret;
+  }
+
+  void Compare(Document* doc, const char* expected) {
+    string output;
+    unique_ptr<CodeWriter> cw = GetStringWriter(&output);
+
+    doc->Write(cw.get());
+
+    if (expected == output) {
+      return; // Success
+    }
+
+    test::PrintDiff(expected, output);
+    FAIL() << "Document contents did not match expected contents";
+  }
+
+  const string file_path_;
+  const string file_contents_;
+  FakeIoDelegate io_delegate_;
+  TypeNamespace types_;
+};
+
+class ComplexTypeInterfaceASTTest : public ASTTest {
+ public:
+  ComplexTypeInterfaceASTTest()
+      : ASTTest("android/os/IComplexTypeInterface.aidl",
+                kComplexTypeInterfaceAIDL) {
+    io_delegate_.SetFileContents("foo/IFooType.aidl",
+                                 "package foo; interface IFooType {}");
+  }
+};
+
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientHeader) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  unique_ptr<Document> doc = internals::BuildClientHeader(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeClientHeaderOutput);
+}
+
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSource) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  unique_ptr<Document> doc = internals::BuildClientSource(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeClientSourceOutput);
+}
+
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerHeader) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  unique_ptr<Document> doc = internals::BuildServerHeader(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeServerHeaderOutput);
+}
+
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSource) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  unique_ptr<Document> doc = internals::BuildServerSource(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeServerSourceOutput);
+}
+
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceHeader) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  unique_ptr<Document> doc = internals::BuildInterfaceHeader(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeInterfaceHeaderOutput);
+}
+
+TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceSource) {
+  unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  unique_ptr<Document> doc = internals::BuildInterfaceSource(types_, *interface);
+  Compare(doc.get(), kExpectedComplexTypeInterfaceSourceOutput);
+}
+
+namespace test_io_handling {
+
+const char kInputPath[] = "a/IFoo.aidl";
+const char kOutputPath[] = "output.cpp";
+const char kHeaderDir[] = "headers";
+const char kInterfaceHeaderRelPath[] = "a/IFoo.h";
+
+}  // namespace test_io_handling
+
+class IoErrorHandlingTest : public ASTTest {
+ public:
+  IoErrorHandlingTest ()
+      : ASTTest(test_io_handling::kInputPath,
+                "package a; interface IFoo {}"),
+        options_(GetOptions()) {}
+
+  const unique_ptr<CppOptions> options_;
+
+ private:
+  static unique_ptr<CppOptions> GetOptions() {
+    using namespace test_io_handling;
+
+    const int argc = 4;
+    const char* cmdline[argc] = {
+      "aidl-cpp", kInputPath, kHeaderDir, kOutputPath
+    };
+    return CppOptions::Parse(argc, cmdline);
+  }
+};
+
+TEST_F(IoErrorHandlingTest, GenerateCorrectlyAbsentErrors) {
+  // Confirm that this is working correctly without I/O problems.
+  const unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+  ASSERT_TRUE(GenerateCpp(*options_, types_, *interface, io_delegate_));
+}
+
+TEST_F(IoErrorHandlingTest, HandlesBadHeaderWrite) {
+  using namespace test_io_handling;
+  const unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+
+  // Simulate issues closing the interface header.
+  const string header_path =
+      StringPrintf("%s%c%s", kHeaderDir, OS_PATH_SEPARATOR,
+                   kInterfaceHeaderRelPath);
+  io_delegate_.AddBrokenFilePath(header_path);
+  ASSERT_FALSE(GenerateCpp(*options_, types_, *interface, io_delegate_));
+  // We should never attempt to write the C++ file if we fail writing headers.
+  ASSERT_FALSE(io_delegate_.GetWrittenContents(kOutputPath, nullptr));
+  // We should remove partial results.
+  ASSERT_TRUE(io_delegate_.PathWasRemoved(header_path));
+}
+
+TEST_F(IoErrorHandlingTest, HandlesBadCppWrite) {
+  using test_io_handling::kOutputPath;
+  const unique_ptr<AidlInterface> interface = Parse();
+  ASSERT_NE(interface, nullptr);
+
+  // Simulate issues closing the cpp file.
+  io_delegate_.AddBrokenFilePath(kOutputPath);
+  ASSERT_FALSE(GenerateCpp(*options_, types_, *interface, io_delegate_));
+  // We should remove partial results.
+  ASSERT_TRUE(io_delegate_.PathWasRemoved(kOutputPath));
+}
+
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/generate_java.cpp b/aidl/generate_java.cpp
new file mode 100644
index 0000000..14df353
--- /dev/null
+++ b/aidl/generate_java.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "generate_java.h"
+
+#include <memory>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <android-base/stringprintf.h>
+
+#include "code_writer.h"
+#include "type_java.h"
+
+using std::unique_ptr;
+using ::android::aidl::java::Variable;
+using std::string;
+using android::base::StringPrintf;
+
+namespace android {
+namespace aidl {
+
+// =================================================
+VariableFactory::VariableFactory(const string& base)
+    : base_(base),
+      index_(0) {
+}
+
+Variable* VariableFactory::Get(const Type* type) {
+  Variable* v = new Variable(
+      type, StringPrintf("%s%d", base_.c_str(), index_));
+  vars_.push_back(v);
+  index_++;
+  return v;
+}
+
+Variable* VariableFactory::Get(int index) {
+  return vars_[index];
+}
+
+namespace java {
+
+int generate_java(const string& filename, const string& originalSrc,
+                  AidlInterface* iface, JavaTypeNamespace* types,
+                  const IoDelegate& io_delegate) {
+  Class* cl = generate_binder_interface_class(iface, types);
+
+  Document* document = new Document(
+      "" /* no comment */,
+      (!iface->GetPackage().empty()) ? iface->GetPackage() : "",
+      originalSrc,
+      unique_ptr<Class>(cl));
+
+  CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
+  document->Write(code_writer.get());
+
+  return 0;
+}
+
+}  // namespace java
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/generate_java.h b/aidl/generate_java.h
new file mode 100644
index 0000000..ed04ba1
--- /dev/null
+++ b/aidl/generate_java.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_GENERATE_JAVA_H_
+#define AIDL_GENERATE_JAVA_H_
+
+#include <string>
+
+#include "aidl_language.h"
+#include "ast_java.h"
+#include "io_delegate.h"
+
+namespace android {
+namespace aidl {
+
+namespace java {
+
+class JavaTypeNamespace;
+
+int generate_java(const std::string& filename, const std::string& originalSrc,
+                  AidlInterface* iface, java::JavaTypeNamespace* types,
+                  const IoDelegate& io_delegate);
+
+android::aidl::java::Class* generate_binder_interface_class(
+    const AidlInterface* iface, java::JavaTypeNamespace* types);
+
+}  // namespace java
+
+class VariableFactory {
+ public:
+  using Variable = ::android::aidl::java::Variable;
+  using Type = ::android::aidl::java::Type;
+
+  explicit VariableFactory(const std::string& base); // base must be short
+  Variable* Get(const Type* type);
+  Variable* Get(int index);
+
+ private:
+  std::vector<Variable*> vars_;
+  std::string base_;
+  int index_;
+
+  DISALLOW_COPY_AND_ASSIGN(VariableFactory);
+};
+
+}  // namespace android
+}  // namespace aidl
+
+#endif // AIDL_GENERATE_JAVA_H_
diff --git a/aidl/generate_java_binder.cpp b/aidl/generate_java_binder.cpp
new file mode 100644
index 0000000..02a6922
--- /dev/null
+++ b/aidl/generate_java_binder.cpp
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "generate_java.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+
+#include <android-base/macros.h>
+
+#include "type_java.h"
+
+using std::string;
+
+namespace android {
+namespace aidl {
+namespace java {
+
+// =================================================
+class StubClass : public Class {
+ public:
+  StubClass(const Type* type, const InterfaceType* interfaceType,
+            JavaTypeNamespace* types);
+  virtual ~StubClass() = default;
+
+  Variable* transact_code;
+  Variable* transact_data;
+  Variable* transact_reply;
+  Variable* transact_flags;
+  SwitchStatement* transact_switch;
+
+ private:
+  void make_as_interface(const InterfaceType* interfaceType,
+                         JavaTypeNamespace* types);
+
+  DISALLOW_COPY_AND_ASSIGN(StubClass);
+};
+
+StubClass::StubClass(const Type* type, const InterfaceType* interfaceType,
+                     JavaTypeNamespace* types)
+    : Class() {
+  this->comment = "/** Local-side IPC implementation stub class. */";
+  this->modifiers = PUBLIC | ABSTRACT | STATIC;
+  this->what = Class::CLASS;
+  this->type = type;
+  this->extends = types->BinderNativeType();
+  this->interfaces.push_back(interfaceType);
+
+  // descriptor
+  Field* descriptor =
+      new Field(STATIC | FINAL | PRIVATE,
+                new Variable(types->StringType(), "DESCRIPTOR"));
+  descriptor->value = "\"" + interfaceType->JavaType() + "\"";
+  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, types);
+
+  // asBinder
+  Method* asBinder = new Method;
+  asBinder->modifiers = PUBLIC | OVERRIDE;
+  asBinder->returnType = types->IBinderType();
+  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(types->IntType(), "code");
+  this->transact_data = new Variable(types->ParcelType(), "data");
+  this->transact_reply = new Variable(types->ParcelType(), "reply");
+  this->transact_flags = new Variable(types->IntType(), "flags");
+  Method* onTransact = new Method;
+  onTransact->modifiers = PUBLIC | OVERRIDE;
+  onTransact->returnType = types->BoolType();
+  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(types->RemoteExceptionType());
+  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));
+}
+
+void StubClass::make_as_interface(const InterfaceType* interfaceType,
+                                  JavaTypeNamespace* types) {
+  Variable* obj = new Variable(types->IBinderType(), "obj");
+
+  Method* m = new Method;
+  m->comment = "/**\n * Cast an IBinder object into an ";
+  m->comment += interfaceType->JavaType();
+  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(types);
+  Variable* iin = new Variable(iinType, "iin");
+  VariableDeclaration* iinVd =
+      new VariableDeclaration(iin, queryLocalInterface, NULL);
+  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->JavaType()));
+  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);
+
+  NewExpression* ne = new NewExpression(interfaceType->GetProxy());
+  ne->arguments.push_back(obj);
+  m->statements->Add(new ReturnStatement(ne));
+
+  this->elements.push_back(m);
+}
+
+// =================================================
+class ProxyClass : public Class {
+ public:
+  ProxyClass(const JavaTypeNamespace* types, const Type* type,
+             const InterfaceType* interfaceType);
+  virtual ~ProxyClass();
+
+  Variable* mRemote;
+  bool mOneWay;
+};
+
+ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type,
+                       const 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(types->IBinderType(), "mRemote");
+  this->elements.push_back(new Field(PRIVATE, mRemote));
+
+  // Proxy()
+  Variable* remote = new Variable(types->IBinderType(), "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 | OVERRIDE;
+  asBinder->returnType = types->IBinderType();
+  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(const Type* t, StatementBlock* addTo,
+                               Variable* v, Variable* parcel,
+                               JavaTypeNamespace* types) {
+  Variable* len = new Variable(types->IntType(), 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(const Type* t, StatementBlock* addTo,
+                                     Variable* v, Variable* parcel, int flags) {
+  t->WriteToParcel(addTo, v, parcel, flags);
+}
+
+static void generate_create_from_parcel(const Type* t, StatementBlock* addTo,
+                                        Variable* v, Variable* parcel,
+                                        Variable** cl) {
+  t->CreateFromParcel(addTo, v, parcel, cl);
+}
+
+static void generate_int_constant(const AidlIntConstant& constant,
+                                  Class* interface) {
+  IntConstant* decl = new IntConstant(constant.GetName(), constant.GetValue());
+  interface->elements.push_back(decl);
+}
+
+static void generate_string_constant(const AidlStringConstant& constant,
+                                     Class* interface) {
+  StringConstant* decl = new StringConstant(constant.GetName(),
+                                            constant.GetValue());
+  interface->elements.push_back(decl);
+}
+
+static void generate_method(const AidlMethod& method, Class* interface,
+                            StubClass* stubClass, ProxyClass* proxyClass,
+                            int index, JavaTypeNamespace* types) {
+  int i;
+
+  const bool oneway = proxyClass->mOneWay || method.IsOneway();
+
+  // == the TRANSACT_ constant =============================================
+  string transactCodeName = "TRANSACTION_";
+  transactCodeName += method.GetName();
+
+  char transactCodeValue[60];
+  sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)",
+          index);
+
+  Field* transactCode = new Field(
+      STATIC | FINAL, new Variable(types->IntType(), transactCodeName));
+  transactCode->value = transactCodeValue;
+  stubClass->elements.push_back(transactCode);
+
+  // == the declaration in the interface ===================================
+  Method* decl = new Method;
+  decl->comment = method.GetComments();
+  decl->modifiers = PUBLIC;
+  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(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
+                     arg->GetType().IsArray() ? 1 : 0));
+  }
+
+  decl->exceptions.push_back(types->RemoteExceptionType());
+
+  interface->elements.push_back(decl);
+
+  // == the stub method ====================================================
+
+  Case* c = new Case(transactCodeName);
+
+  MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName());
+
+  // 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");
+  for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
+    const Type* t = arg->GetType().GetLanguageType<Type>();
+    Variable* v = stubArgs.Get(t);
+    v->dimension = arg->GetType().IsArray() ? 1 : 0;
+
+    c->statements->Add(new VariableDeclaration(v));
+
+    if (arg->GetDirection() & AidlArgument::IN_DIR) {
+      generate_create_from_parcel(t, c->statements, v, stubClass->transact_data,
+                                  &cl);
+    } else {
+      if (!arg->GetType().IsArray()) {
+        c->statements->Add(new Assignment(v, new NewExpression(v->type)));
+      } else {
+        generate_new_array(v->type, c->statements, v, stubClass->transact_data,
+                           types);
+      }
+    }
+
+    realCall->arguments.push_back(v);
+  }
+
+  // the real call
+  Variable* _result = NULL;
+  if (method.GetType().GetName() == "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;
+  for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
+    const Type* t = arg->GetType().GetLanguageType<Type>();
+    Variable* v = stubArgs.Get(i++);
+
+    if (arg->GetDirection() & AidlArgument::OUT_DIR) {
+      generate_write_to_parcel(t, c->statements, v, stubClass->transact_reply,
+                               Type::PARCELABLE_WRITE_RETURN_VALUE);
+    }
+  }
+
+  // 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 = method.GetComments();
+  proxy->modifiers = PUBLIC | OVERRIDE;
+  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(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
+                     arg->GetType().IsArray() ? 1 : 0));
+  }
+  proxy->exceptions.push_back(types->RemoteExceptionType());
+  proxyClass->elements.push_back(proxy);
+
+  // the parcels
+  Variable* _data = new Variable(types->ParcelType(), "_data");
+  proxy->statements->Add(new VariableDeclaration(
+      _data, new MethodCall(types->ParcelType(), "obtain")));
+  Variable* _reply = NULL;
+  if (!oneway) {
+    _reply = new Variable(types->ParcelType(), "_reply");
+    proxy->statements->Add(new VariableDeclaration(
+        _reply, new MethodCall(types->ParcelType(), "obtain")));
+  }
+
+  // the return value
+  _result = NULL;
+  if (method.GetType().GetName() != "void") {
+    _result = new Variable(proxy->returnType, "_result",
+                           method.GetType().IsArray() ? 1 : 0);
+    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
+  for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
+    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()) {
+      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 & AidlArgument::IN_DIR) {
+      generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
+    } else {
+      delete v;
+    }
+  }
+
+  // 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
+    for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
+      const Type* t = arg->GetType().GetLanguageType<Type>();
+      if (arg->GetDirection() & AidlArgument::OUT_DIR) {
+        Variable* v =
+            new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
+        t->ReadFromParcel(tryStatement->statements, v, _reply, &cl);
+      }
+    }
+
+    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,
+                                           const JavaTypeNamespace* types) {
+  // 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 = types->StringType();
+  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 AidlInterface* iface,
+                                       JavaTypeNamespace* types) {
+  const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
+
+  // the interface class
+  Class* interface = new Class;
+  interface->comment = iface->GetComments();
+  interface->modifiers = PUBLIC;
+  interface->what = Class::INTERFACE;
+  interface->type = interfaceType;
+  interface->interfaces.push_back(types->IInterfaceType());
+
+  // the stub inner class
+  StubClass* stub =
+      new StubClass(interfaceType->GetStub(), interfaceType, types);
+  interface->elements.push_back(stub);
+
+  // the proxy inner class
+  ProxyClass* proxy =
+      new ProxyClass(types, interfaceType->GetProxy(), interfaceType);
+  stub->elements.push_back(proxy);
+
+  // stub and proxy support for getInterfaceDescriptor()
+  generate_interface_descriptors(stub, proxy, types);
+
+  // all the declared constants of the interface
+  for (const auto& item : iface->GetIntConstants()) {
+    generate_int_constant(*item, interface);
+  }
+  for (const auto& item : iface->GetStringConstants()) {
+    generate_string_constant(*item, interface);
+  }
+
+  // all the declared methods of the interface
+  for (const auto& item : iface->GetMethods()) {
+    generate_method(*item, interface, stub, proxy, item->GetId(), types);
+  }
+
+  return interface;
+}
+
+}  // namespace java
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/import_resolver.cpp b/aidl/import_resolver.cpp
new file mode 100644
index 0000000..4957c76
--- /dev/null
+++ b/aidl/import_resolver.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "import_resolver.h"
+
+#include <unistd.h>
+
+#ifdef _WIN32
+#include <io.h>
+#endif
+
+#include "os.h"
+
+using std::string;
+using std::vector;
+
+namespace android {
+namespace aidl {
+
+ImportResolver::ImportResolver(const IoDelegate& io_delegate,
+                               const vector<string>& import_paths)
+    : io_delegate_(io_delegate) {
+  for (string path : import_paths) {
+    if (path.empty()) {
+      path = ".";
+    }
+    if (path[path.size() - 1] != OS_PATH_SEPARATOR) {
+      path += OS_PATH_SEPARATOR;
+    }
+    import_paths_.push_back(std::move(path));
+  }
+}
+
+
+string ImportResolver::FindImportFile(const string& canonical_name) const {
+  // Convert the canonical name to a relative file path.
+  string relative_path = canonical_name;
+  for (char& c : relative_path) {
+    if (c == '.') {
+      c = OS_PATH_SEPARATOR;
+    }
+  }
+  relative_path += ".aidl";
+
+  // Look for that relative path at each of our import roots.
+  for (string path : import_paths_) {
+    path = path + relative_path;
+    if (io_delegate_.FileIsReadable(path)) {
+      return path;
+    }
+  }
+
+  return "";
+}
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/import_resolver.h b/aidl/import_resolver.h
new file mode 100644
index 0000000..e7562fb
--- /dev/null
+++ b/aidl/import_resolver.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_IMPORT_RESOLVER_H_
+#define AIDL_IMPORT_RESOLVER_H_
+
+#include <string>
+#include <vector>
+
+#include <android-base/macros.h>
+
+#include "io_delegate.h"
+
+namespace android {
+namespace aidl {
+
+class ImportResolver {
+ public:
+  ImportResolver(const IoDelegate& io_delegate,
+                 const std::vector<std::string>& import_paths);
+  virtual ~ImportResolver() = default;
+
+  // Resolve the canonical name for a class to a file that exists
+  // in one of the import paths given to the ImportResolver.
+  std::string FindImportFile(const std::string& canonical_name) const;
+
+ private:
+  const IoDelegate& io_delegate_;
+  std::vector<std::string> import_paths_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImportResolver);
+};
+
+}  // namespace android
+}  // namespace aidl
+
+#endif // AIDL_IMPORT_RESOLVER_H_
diff --git a/aidl/io_delegate.cpp b/aidl/io_delegate.cpp
new file mode 100644
index 0000000..62be3f5
--- /dev/null
+++ b/aidl/io_delegate.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io_delegate.h"
+
+#include <cstring>
+#include <fstream>
+#include <vector>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <android-base/strings.h>
+
+#include "logging.h"
+#include "os.h"
+
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+using android::base::Split;
+
+namespace android {
+namespace aidl {
+
+bool IoDelegate::GetAbsolutePath(const string& path, string* absolute_path) {
+#ifdef _WIN32
+
+  char buf[4096];
+  DWORD path_len = GetFullPathName(path.c_str(), sizeof(buf), buf, nullptr);
+  if (path_len <= 0 || path_len >= sizeof(buf)) {
+    LOG(ERROR) << "Failed to GetFullPathName(" << path << ")";
+    return false;
+  }
+  *absolute_path = buf;
+
+  return true;
+
+#else
+
+  if (path.empty()) {
+    LOG(ERROR) << "Giving up on finding an absolute path to represent the "
+                  "empty string.";
+    return false;
+  }
+  if (path[0] == OS_PATH_SEPARATOR) {
+    *absolute_path = path;
+    return true;
+  }
+
+  char buf[4096];
+  if (getcwd(buf, sizeof(buf)) == nullptr) {
+    LOG(ERROR) << "Path of current working directory does not fit in "
+               << sizeof(buf) << " bytes";
+    return false;
+  }
+
+  *absolute_path = buf;
+  *absolute_path += OS_PATH_SEPARATOR;
+  *absolute_path += path;
+  return true;
+#endif
+}
+
+unique_ptr<string> IoDelegate::GetFileContents(
+    const string& filename,
+    const string& content_suffix) const {
+  unique_ptr<string> contents;
+  std::ifstream in(filename, std::ios::in | std::ios::binary);
+  if (!in) {
+    return contents;
+  }
+  contents.reset(new string);
+  in.seekg(0, std::ios::end);
+  ssize_t file_size = in.tellg();
+  contents->resize(file_size + content_suffix.length());
+  in.seekg(0, std::ios::beg);
+  // Read the file contents into the beginning of the string
+  in.read(&(*contents)[0], file_size);
+  // Drop the suffix in at the end.
+  contents->replace(file_size, content_suffix.length(), content_suffix);
+  in.close();
+
+  return contents;
+}
+
+unique_ptr<LineReader> IoDelegate::GetLineReader(
+    const string& file_path) const {
+  return LineReader::ReadFromFile(file_path);
+}
+
+bool IoDelegate::FileIsReadable(const string& path) const {
+#ifdef _WIN32
+  // check that the file exists and is not write-only
+  return (0 == _access(path.c_str(), 0)) &&  // mode 0=exist
+         (0 == _access(path.c_str(), 4));    // mode 4=readable
+#else
+  return (0 == access(path.c_str(), R_OK));
+#endif
+}
+
+bool IoDelegate::CreatedNestedDirs(
+    const string& caller_base_dir,
+    const vector<string>& nested_subdirs) const {
+  string base_dir = caller_base_dir;
+  if (base_dir.empty()) {
+    base_dir = ".";
+  }
+  for (const string& subdir : nested_subdirs) {
+    if (base_dir[base_dir.size() - 1] != OS_PATH_SEPARATOR) {
+      base_dir += OS_PATH_SEPARATOR;
+    }
+    base_dir += subdir;
+    bool success;
+#ifdef _WIN32
+    success = _mkdir(base_dir.c_str()) == 0;
+#else
+    success = mkdir(base_dir.c_str(),
+                    S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
+#endif
+    // On darwin when you try to mkdir("/", ...) we get EISDIR.
+    if (!success && (errno != EEXIST && errno != EISDIR)) {
+      LOG(ERROR) << "Error while creating " << base_dir << ": "
+                 << strerror(errno);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IoDelegate::CreatePathForFile(const string& path) const {
+  if (path.empty()) {
+    return true;
+  }
+
+  string absolute_path;
+  if (!GetAbsolutePath(path, &absolute_path)) {
+    return false;
+  }
+
+  auto directories = Split(absolute_path, string{1u, OS_PATH_SEPARATOR});
+
+  // The "base" directory is just the root of the file system.  On Windows,
+  // this will look like "C:\" but on Unix style file systems we get an empty
+  // string after splitting "/foo" with "/"
+  string base = directories[0];
+  if (base.empty()) {
+    base = "/";
+  }
+  directories.erase(directories.begin());
+
+  // Remove the actual file in question, we're just creating the directory path.
+  directories.pop_back();
+
+  return CreatedNestedDirs(base, directories);
+}
+
+unique_ptr<CodeWriter> IoDelegate::GetCodeWriter(
+    const string& file_path) const {
+  return GetFileWriter(file_path);
+}
+
+void IoDelegate::RemovePath(const std::string& file_path) const {
+#ifdef _WIN32
+  _unlink(file_path.c_str());
+#else
+  unlink(file_path.c_str());
+#endif
+}
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/io_delegate.h b/aidl/io_delegate.h
new file mode 100644
index 0000000..dc9a3e3
--- /dev/null
+++ b/aidl/io_delegate.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_IO_DELEGATE_H_
+#define AIDL_IO_DELEGATE_H_
+
+#include <android-base/macros.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "code_writer.h"
+#include "line_reader.h"
+
+namespace android {
+namespace aidl {
+
+class IoDelegate {
+ public:
+  IoDelegate() = default;
+  virtual ~IoDelegate() = default;
+
+  // Stores an absolute version of |path| to |*absolute_path|,
+  // possibly prefixing it with the current working directory.
+  // Returns false and does not set |*absolute_path| on error.
+  static bool GetAbsolutePath(const std::string& path,
+                              std::string* absolute_path);
+
+  // Returns a unique_ptr to the contents of |filename|.
+  // Will append the optional |content_suffix| to the returned contents.
+  virtual std::unique_ptr<std::string> GetFileContents(
+      const std::string& filename,
+      const std::string& content_suffix = "") const;
+
+  virtual std::unique_ptr<LineReader> GetLineReader(
+      const std::string& file_path) const;
+
+  virtual bool FileIsReadable(const std::string& path) const;
+
+  virtual bool CreatedNestedDirs(
+      const std::string& base_dir,
+      const std::vector<std::string>& nested_subdirs) const;
+
+  bool CreatePathForFile(const std::string& path) const;
+
+  virtual std::unique_ptr<CodeWriter> GetCodeWriter(
+      const std::string& file_path) const;
+
+  virtual void RemovePath(const std::string& file_path) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IoDelegate);
+};  // class IoDelegate
+
+}  // namespace android
+}  // namespace aidl
+
+#endif // AIDL_IO_DELEGATE_H_
diff --git a/aidl/io_delegate_unittest.cpp b/aidl/io_delegate_unittest.cpp
new file mode 100644
index 0000000..5227d0b
--- /dev/null
+++ b/aidl/io_delegate_unittest.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "io_delegate.h"
+
+using std::string;
+
+namespace android {
+namespace aidl {
+
+TEST(IoDelegateTest, CannotGetAbsolutePathFromEmptyString) {
+  string absolute_path;
+  EXPECT_FALSE(IoDelegate::GetAbsolutePath("", &absolute_path));
+  EXPECT_TRUE(absolute_path.empty());
+}
+
+TEST(IoDelegateTest, CurrentlyInfersLinuxAbsolutePath) {
+  string absolute_path;
+  EXPECT_TRUE(IoDelegate::GetAbsolutePath("foo", &absolute_path));
+  ASSERT_FALSE(absolute_path.empty());
+  // Should find our desired file at the end of |absolute_path|
+  // But we don't know the prefix, since it's the current working directory
+  EXPECT_TRUE(absolute_path.rfind("/foo") == absolute_path.length() - 4);
+  // Whatever our current working directory, the path is absolute.
+  EXPECT_EQ(absolute_path[0], '/');
+}
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/line_reader.cpp b/aidl/line_reader.cpp
new file mode 100644
index 0000000..0bcaa1d
--- /dev/null
+++ b/aidl/line_reader.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "line_reader.h"
+
+#include <fstream>
+#include <sstream>
+
+using std::istringstream;
+using std::ifstream;
+using std::string;
+using std::unique_ptr;
+
+namespace android {
+namespace aidl {
+
+class FileLineReader : public LineReader {
+ public:
+  FileLineReader() = default;
+  virtual ~FileLineReader() {
+    input_stream_.close();
+  }
+
+  bool Init(const std::string& file_path) {
+    input_stream_.open(file_path, ifstream::in | ifstream::binary);
+    return input_stream_.is_open() && input_stream_.good();
+  }
+
+  bool ReadLine(string* line) override {
+    if (!input_stream_.good()) {
+      return false;
+    }
+    line->clear();
+    std::getline(input_stream_, *line);
+    return true;
+  }
+
+ private:
+  ifstream input_stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileLineReader);
+};  // class FileLineReader
+
+class MemoryLineReader : public LineReader {
+ public:
+  explicit MemoryLineReader(const string& contents) : input_stream_(contents) {}
+  virtual ~MemoryLineReader() = default;
+
+  bool ReadLine(string* line) override {
+    if (!input_stream_.good()) {
+      return false;
+    }
+    line->clear();
+    std::getline(input_stream_, *line);
+    return true;
+  }
+
+ private:
+  istringstream input_stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryLineReader);
+};  // class MemoryLineReader
+
+unique_ptr<LineReader> LineReader::ReadFromFile(const string& file_path) {
+  unique_ptr<FileLineReader> file_reader(new FileLineReader());
+  unique_ptr<LineReader> ret;
+  if (file_reader->Init(file_path)) {
+    ret.reset(file_reader.release());
+  }
+  return ret;
+}
+
+unique_ptr<LineReader> LineReader::ReadFromMemory(const string& contents) {
+  return unique_ptr<LineReader>(new MemoryLineReader(contents));
+}
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/line_reader.h b/aidl/line_reader.h
new file mode 100644
index 0000000..885327e
--- /dev/null
+++ b/aidl/line_reader.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_LINE_READER_H_
+#define AIDL_LINE_READER_H_
+
+#include <memory>
+#include <string>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace aidl {
+
+class LineReader {
+ public:
+  LineReader() = default;
+  virtual ~LineReader() = default;
+  virtual bool ReadLine(std::string* line) = 0;
+
+  static std::unique_ptr<LineReader> ReadFromFile(
+      const std::string& file_path);
+  static std::unique_ptr<LineReader> ReadFromMemory(
+      const std::string& contents);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LineReader);
+};  // class LineReader
+
+}  // namespace android
+}  // namespace aidl
+
+#endif // AIDL_LINE_READER_H_
diff --git a/aidl/logging.h b/aidl/logging.h
new file mode 100644
index 0000000..f76c4e0
--- /dev/null
+++ b/aidl/logging.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_LOGGING_H_
+#define AIDL_LOGGING_H_
+
+// We must include windows.h before android-base/logging.h on Windows.
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <android-base/logging.h>
+
+#endif // AIDL_LOGGING_H_
diff --git a/aidl/main_cpp.cpp b/aidl/main_cpp.cpp
new file mode 100644
index 0000000..790efdc
--- /dev/null
+++ b/aidl/main_cpp.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+
+#include "aidl.h"
+#include "io_delegate.h"
+#include "logging.h"
+#include "options.h"
+
+using android::aidl::CppOptions;
+
+int main(int argc, char** argv) {
+  android::base::InitLogging(argv);
+  LOG(DEBUG) << "aidl starting";
+
+  std::unique_ptr<CppOptions> options = CppOptions::Parse(argc, argv);
+  if (!options) {
+    return 1;
+  }
+
+  android::aidl::IoDelegate io_delegate;
+  return android::aidl::compile_aidl_to_cpp(*options, io_delegate);
+}
diff --git a/aidl/main_java.cpp b/aidl/main_java.cpp
new file mode 100644
index 0000000..7d32b24
--- /dev/null
+++ b/aidl/main_java.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <memory>
+
+#include "aidl.h"
+#include "io_delegate.h"
+#include "logging.h"
+#include "options.h"
+
+using android::aidl::JavaOptions;
+
+int main(int argc, char** argv) {
+  android::base::InitLogging(argv);
+  LOG(DEBUG) << "aidl starting";
+  std::unique_ptr<JavaOptions> options = JavaOptions::Parse(argc, argv);
+  if (!options) {
+    return 1;
+  }
+
+  android::aidl::IoDelegate io_delegate;
+  switch (options->task) {
+    case JavaOptions::COMPILE_AIDL_TO_JAVA:
+      return android::aidl::compile_aidl_to_java(*options, io_delegate);
+    case JavaOptions::PREPROCESS_AIDL:
+      if (android::aidl::preprocess_aidl(*options, io_delegate))
+        return 0;
+      return 1;
+  }
+  std::cerr << "aidl: internal error" << std::endl;
+  return 1;
+}
diff --git a/aidl/options.cpp b/aidl/options.cpp
new file mode 100644
index 0000000..c7cef5c
--- /dev/null
+++ b/aidl/options.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "options.h"
+
+#include <cstring>
+#include <iostream>
+#include <stdio.h>
+
+#include "logging.h"
+#include "os.h"
+
+using std::cerr;
+using std::endl;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace {
+
+unique_ptr<JavaOptions> java_usage() {
+  fprintf(stderr,
+          "usage: aidl OPTIONS INPUT [OUTPUT]\n"
+          "       aidl --preprocess OUTPUT INPUT...\n"
+          "\n"
+          "OPTIONS:\n"
+          "   -I<DIR>    search path for import statements.\n"
+          "   -d<FILE>   generate dependency file.\n"
+          "   -a         generate dependency file next to the output file with "
+          "the name based on the input file.\n"
+          "   -p<FILE>   file created by --preprocess to import.\n"
+          "   -o<FOLDER> base output folder for generated files.\n"
+          "   -b         fail when trying to compile a parcelable.\n"
+          "\n"
+          "INPUT:\n"
+          "   An aidl interface file.\n"
+          "\n"
+          "OUTPUT:\n"
+          "   The generated interface files.\n"
+          "   If omitted and the -o option is not used, the input filename is "
+          "used, with the .aidl extension changed to a .java extension.\n"
+          "   If the -o option is used, the generated files will be placed in "
+          "the base output folder, under their package folder\n");
+  return unique_ptr<JavaOptions>(nullptr);
+}
+
+}  // namespace
+
+unique_ptr<JavaOptions> JavaOptions::Parse(int argc, const char* const* argv) {
+  unique_ptr<JavaOptions> options(new JavaOptions());
+  int i = 1;
+
+  if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) {
+    if (argc < 4) {
+      return java_usage();
+    }
+    options->output_file_name_ = argv[2];
+    for (int i = 3; i < argc; i++) {
+      options->files_to_preprocess_.push_back(argv[i]);
+    }
+    options->task = PREPROCESS_AIDL;
+    return options;
+  }
+
+  options->task = COMPILE_AIDL_TO_JAVA;
+  // OPTIONS
+  while (i < argc) {
+    const char* s = argv[i];
+    const size_t len = strlen(s);
+    if (s[0] != '-') {
+      break;
+    }
+    if (len <= 1) {
+      fprintf(stderr, "unknown option (%d): %s\n", i, s);
+      return java_usage();
+    }
+    // -I<system-import-path>
+    if (s[1] == 'I') {
+      if (len > 2) {
+        options->import_paths_.push_back(s + 2);
+      } else {
+        fprintf(stderr, "-I option (%d) requires a path.\n", i);
+        return java_usage();
+      }
+    } else if (s[1] == 'd') {
+      if (len > 2) {
+        options->dep_file_name_ = s + 2;
+      } else {
+        fprintf(stderr, "-d option (%d) requires a file.\n", i);
+        return java_usage();
+      }
+    } else if (strcmp(s, "-a") == 0) {
+      options->auto_dep_file_ = true;
+    } else if (s[1] == 'p') {
+      if (len > 2) {
+        options->preprocessed_files_.push_back(s + 2);
+      } else {
+        fprintf(stderr, "-p option (%d) requires a file.\n", i);
+        return java_usage();
+      }
+    } else if (s[1] == 'o') {
+      if (len > 2) {
+        options->output_base_folder_= s + 2;
+      } else {
+        fprintf(stderr, "-o option (%d) requires a path.\n", i);
+        return java_usage();
+      }
+    } else if (strcmp(s, "-b") == 0) {
+      options->fail_on_parcelable_ = true;
+    } else {
+      // s[1] is not known
+      fprintf(stderr, "unknown option (%d): %s\n", i, s);
+      return java_usage();
+    }
+    i++;
+  }
+  // INPUT
+  if (i < argc) {
+    options->input_file_name_ = argv[i];
+    i++;
+  } else {
+    fprintf(stderr, "INPUT required\n");
+    return java_usage();
+  }
+  if (!EndsWith(options->input_file_name_, ".aidl")) {
+    cerr << "Expected .aidl file for input but got "
+         << options->input_file_name_ << endl;
+    return java_usage();
+  }
+
+  // OUTPUT
+  if (i < argc) {
+    options->output_file_name_ = argv[i];
+    i++;
+  } else if (options->output_base_folder_.empty()) {
+    // copy input into output and change the extension from .aidl to .java
+    options->output_file_name_= options->input_file_name_;
+    if (!ReplaceSuffix(".aidl", ".java", &options->output_file_name_)) {
+      // we should never get here since we validated the suffix.
+      LOG(FATAL) << "Internal aidl error.";
+      return java_usage();
+    }
+  }
+
+  // anything remaining?
+  if (i != argc) {
+    fprintf(stderr, "unknown option%s:",
+            (i == argc - 1 ? (const char*)"" : (const char*)"s"));
+    for (; i < argc - 1; i++) {
+      fprintf(stderr, " %s", argv[i]);
+    }
+    fprintf(stderr, "\n");
+    return java_usage();
+  }
+
+  return options;
+}
+
+string JavaOptions::DependencyFilePath() const {
+  if (auto_dep_file_) {
+    return output_file_name_ + ".d";
+  }
+  return dep_file_name_;
+}
+
+namespace {
+
+unique_ptr<CppOptions> cpp_usage() {
+  cerr << "usage: aidl-cpp INPUT_FILE HEADER_DIR OUTPUT_FILE" << endl
+       << endl
+       << "OPTIONS:" << endl
+       << "   -I<DIR>   search path for import statements" << endl
+       << "   -d<FILE>  generate dependency file" << endl
+       << endl
+       << "INPUT_FILE:" << endl
+       << "   an aidl interface file" << endl
+       << "HEADER_DIR:" << endl
+       << "   empty directory to put generated headers" << endl
+       << "OUTPUT_FILE:" << endl
+       << "   path to write generated .cpp code" << endl;
+  return unique_ptr<CppOptions>(nullptr);
+}
+
+}  // namespace
+
+unique_ptr<CppOptions> CppOptions::Parse(int argc, const char* const* argv) {
+  unique_ptr<CppOptions> options(new CppOptions());
+  int i = 1;
+
+  // Parse flags, all of which start with '-'
+  for ( ; i < argc; ++i) {
+    const size_t len = strlen(argv[i]);
+    const char *s = argv[i];
+    if (s[0] != '-') {
+      break;  // On to the positional arguments.
+    }
+    if (len < 2) {
+      cerr << "Invalid argument '" << s << "'." << endl;
+      return cpp_usage();
+    }
+    const string the_rest = s + 2;
+    if (s[1] == 'I') {
+      options->import_paths_.push_back(the_rest);
+    } else if (s[1] == 'd') {
+      options->dep_file_name_ = the_rest;
+    } else {
+      cerr << "Invalid argument '" << s << "'." << endl;
+      return cpp_usage();
+    }
+  }
+
+  // There are exactly three positional arguments.
+  const int remaining_args = argc - i;
+  if (remaining_args != 3) {
+    cerr << "Expected 3 positional arguments but got " << remaining_args << "." << endl;
+    return cpp_usage();
+  }
+
+  options->input_file_name_ = argv[i];
+  options->output_header_dir_ = argv[i + 1];
+  options->output_file_name_ = argv[i + 2];
+
+  if (!EndsWith(options->input_file_name_, ".aidl")) {
+    cerr << "Expected .aidl file for input but got " << options->input_file_name_ << endl;
+    return cpp_usage();
+  }
+
+  return options;
+}
+
+bool EndsWith(const string& str, const string& suffix) {
+  if (str.length() < suffix.length()) {
+    return false;
+  }
+  return std::equal(str.crbegin(), str.crbegin() + suffix.length(),
+                    suffix.crbegin());
+}
+
+bool ReplaceSuffix(const string& old_suffix,
+                   const string& new_suffix,
+                   string* str) {
+  if (!EndsWith(*str, old_suffix)) return false;
+  str->replace(str->length() - old_suffix.length(),
+               old_suffix.length(),
+               new_suffix);
+  return true;
+}
+
+
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/options.h b/aidl/options.h
new file mode 100644
index 0000000..6f32c62
--- /dev/null
+++ b/aidl/options.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_OPTIONS_H_
+#define AIDL_OPTIONS_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <gtest/gtest_prod.h>
+
+namespace android {
+namespace aidl {
+
+// This object represents the parsed options to the Java generating aidl.
+class JavaOptions final {
+ public:
+  enum {
+      COMPILE_AIDL_TO_JAVA,
+      PREPROCESS_AIDL,
+  };
+
+  ~JavaOptions() = default;
+
+  // Parses the command line and returns a non-null pointer to an JavaOptions
+  // object on success.
+  // Prints the usage statement on failure.
+  static std::unique_ptr<JavaOptions> Parse(int argc, const char* const* argv);
+
+  std::string DependencyFilePath() const;
+
+  int task{COMPILE_AIDL_TO_JAVA};
+  bool fail_on_parcelable_{false};
+  std::vector<std::string> import_paths_;
+  std::vector<std::string> preprocessed_files_;
+  std::string input_file_name_;
+  std::string output_file_name_;
+  std::string output_base_folder_;
+  std::string dep_file_name_;
+  bool auto_dep_file_{false};
+  std::vector<std::string> files_to_preprocess_;
+
+ private:
+  JavaOptions() = default;
+
+  FRIEND_TEST(EndToEndTest, IExampleInterface);
+  FRIEND_TEST(AidlTest, FailOnParcelable);
+  FRIEND_TEST(AidlTest, WritePreprocessedFile);
+  FRIEND_TEST(AidlTest, WritesCorrectDependencyFile);
+  FRIEND_TEST(AidlTest, WritesTrivialDependencyFileForParcelable);
+
+  DISALLOW_COPY_AND_ASSIGN(JavaOptions);
+};
+
+class CppOptions final {
+ public:
+
+  ~CppOptions() = default;
+
+  // Parses the command line and returns a non-null pointer to an CppOptions
+  // object on success.
+  // Prints the usage statement on failure.
+  static std::unique_ptr<CppOptions> Parse(int argc, const char* const* argv);
+
+  std::string InputFileName() const { return input_file_name_; }
+  std::string OutputHeaderDir() const { return output_header_dir_; }
+  std::string OutputCppFilePath() const { return output_file_name_; }
+
+  std::vector<std::string> ImportPaths() const { return import_paths_; }
+  std::string DependencyFilePath() const { return dep_file_name_; }
+
+ private:
+  CppOptions() = default;
+
+  std::string input_file_name_;
+  std::vector<std::string> import_paths_;
+  std::string output_header_dir_;
+  std::string output_file_name_;
+  std::string dep_file_name_;
+
+  FRIEND_TEST(CppOptionsTests, ParsesCompileCpp);
+  DISALLOW_COPY_AND_ASSIGN(CppOptions);
+};
+
+bool EndsWith(const std::string& str, const std::string& suffix);
+bool ReplaceSuffix(const std::string& old_suffix,
+                   const std::string& new_suffix,
+                   std::string* str);
+
+}  // namespace android
+}  // namespace aidl
+
+#endif // AIDL_OPTIONS_H_
diff --git a/aidl/options_unittest.cpp b/aidl/options_unittest.cpp
new file mode 100644
index 0000000..568765b
--- /dev/null
+++ b/aidl/options_unittest.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "options.h"
+
+using std::cerr;
+using std::endl;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace {
+
+const char kPreprocessCommandOutputFile[] = "output_file_name";
+const char kPreprocessCommandInput1[] = "input1";
+const char kPreprocessCommandInput2[] = "input2";
+const char kPreprocessCommandInput3[] = "input3";
+const char* kPreprocessCommand[] = {
+    "aidl", "--preprocess",
+    kPreprocessCommandOutputFile,
+    kPreprocessCommandInput1,
+    kPreprocessCommandInput2,
+    kPreprocessCommandInput3,
+    nullptr,
+};
+
+const char kCompileCommandInput[] = "directory/ITool.aidl";
+const char kCompileCommandIncludePath[] = "-Iinclude_path";
+const char* kCompileJavaCommand[] = {
+    "aidl",
+    "-b",
+    kCompileCommandIncludePath,
+    kCompileCommandInput,
+    nullptr,
+};
+const char kCompileCommandJavaOutput[] = "directory/ITool.java";
+
+const char kCompileDepFile[] = "-doutput.deps";
+const char kCompileCommandHeaderDir[] = "output/dir";
+const char kCompileCommandCppOutput[] = "some/file.cpp";
+const char* kCompileCppCommand[] = {
+    "aidl-cpp",
+    kCompileCommandIncludePath,
+    kCompileDepFile,
+    kCompileCommandInput,
+    kCompileCommandHeaderDir,
+    kCompileCommandCppOutput,
+    nullptr,
+};
+
+template <typename T>
+unique_ptr<T> GetOptions(const char* command[]) {
+  int argc = 0;
+  const char** command_part = command;
+  for (; *command_part; ++argc, ++command_part) {}
+  unique_ptr<T> options(T::Parse(argc, command));
+  if (!options) {
+    cerr << "Failed to parse command line:";
+    for (int i = 0; i < argc; ++i) {
+      cerr << " " << command[i];
+      cerr << endl;
+    }
+  }
+  EXPECT_NE(options, nullptr) << "Failed to parse options!";
+  return options;
+}
+
+}  // namespace
+
+TEST(JavaOptionsTests, ParsesPreprocess) {
+  unique_ptr<JavaOptions> options = GetOptions<JavaOptions>(kPreprocessCommand);
+  EXPECT_EQ(JavaOptions::PREPROCESS_AIDL, options->task);
+  EXPECT_EQ(false, options->fail_on_parcelable_);
+  EXPECT_EQ(0u, options->import_paths_.size());
+  EXPECT_EQ(0u, options->preprocessed_files_.size());
+  EXPECT_EQ(string{}, options->input_file_name_);
+  EXPECT_EQ(string{kPreprocessCommandOutputFile}, options->output_file_name_);
+  EXPECT_EQ(false, options->auto_dep_file_);
+  const vector<string> expected_input{kPreprocessCommandInput1,
+                                      kPreprocessCommandInput2,
+                                      kPreprocessCommandInput3};
+  EXPECT_EQ(expected_input, options->files_to_preprocess_);
+}
+
+TEST(JavaOptionsTests, ParsesCompileJava) {
+  unique_ptr<JavaOptions> options =
+      GetOptions<JavaOptions>(kCompileJavaCommand);
+  EXPECT_EQ(JavaOptions::COMPILE_AIDL_TO_JAVA, options->task);
+  EXPECT_EQ(true, options->fail_on_parcelable_);
+  EXPECT_EQ(1u, options->import_paths_.size());
+  EXPECT_EQ(0u, options->preprocessed_files_.size());
+  EXPECT_EQ(string{kCompileCommandInput}, options->input_file_name_);
+  EXPECT_EQ(string{kCompileCommandJavaOutput}, options->output_file_name_);
+  EXPECT_EQ(false, options->auto_dep_file_);
+}
+
+TEST(CppOptionsTests, ParsesCompileCpp) {
+  unique_ptr<CppOptions> options = GetOptions<CppOptions>(kCompileCppCommand);
+  ASSERT_EQ(1u, options->import_paths_.size());
+  EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2),
+            options->import_paths_[0]);
+  EXPECT_EQ(string{kCompileDepFile}.substr(2), options->dep_file_name_);
+  EXPECT_EQ(kCompileCommandInput, options->InputFileName());
+  EXPECT_EQ(kCompileCommandHeaderDir, options->OutputHeaderDir());
+  EXPECT_EQ(kCompileCommandCppOutput, options->OutputCppFilePath());
+}
+
+TEST(OptionsTests, EndsWith) {
+  EXPECT_TRUE(EndsWith("foo", ""));
+  EXPECT_TRUE(EndsWith("foo", "o"));
+  EXPECT_TRUE(EndsWith("foo", "foo"));
+  EXPECT_FALSE(EndsWith("foo", "fooo"));
+  EXPECT_FALSE(EndsWith("", "o"));
+  EXPECT_TRUE(EndsWith("", ""));
+}
+
+TEST(OptionsTests, ReplaceSuffix) {
+  struct test_case_t {
+    const char* input;
+    const char* old_suffix;
+    const char* new_suffix;
+    const char* result;
+  };
+  const size_t kNumCases = 3;
+  test_case_t kTestInput[kNumCases] = {
+    {"foo.bar", "bar", "foo", "foo.foo"},
+    {"whole", "whole", "new", "new"},
+    {"", "", "", ""},
+  };
+  for (const auto& test_case : kTestInput) {
+    string mutated = test_case.input;
+    EXPECT_TRUE(ReplaceSuffix(test_case.old_suffix,
+                              test_case.new_suffix,
+                              &mutated));
+    EXPECT_EQ(mutated, test_case.result);
+  }
+}
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/os.h b/aidl/os.h
new file mode 100644
index 0000000..752ed47
--- /dev/null
+++ b/aidl/os.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_OS_H_
+#define AIDL_OS_H_
+
+#if defined(_WIN32)
+#define OS_PATH_SEPARATOR '\\'
+#else
+#define OS_PATH_SEPARATOR '/'
+#endif
+
+#endif  // AIDL_OS_H_
diff --git a/aidl/runtests.sh b/aidl/runtests.sh
new file mode 100755
index 0000000..05809f9
--- /dev/null
+++ b/aidl/runtests.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+
+echo "Running tests"
+set -e # fail early
+
+# NOTE We can't actually run these commands, since they rely on functions added
+#      by build/envsetup.sh to the bash shell environment.
+echo "+ mmma -j32 $ANDROID_BUILD_TOP/system/tools/aidl"
+make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \
+    MODULES-IN-system-tools-aidl
+
+set -x # print commands
+
+${ANDROID_HOST_OUT}/nativetest64/aidl_unittests/aidl_unittests
+
+adb root
+adb wait-for-device
+adb remount
+adb sync
+adb install -r \
+    ${ANDROID_PRODUCT_OUT}/system/app/aidl_test_services/aidl_test_services.apk
+${ANDROID_BUILD_TOP}/system/tools/aidl/tests/integration-test.py
diff --git a/aidl/tests/aidl_test_client.cpp b/aidl/tests/aidl_test_client.cpp
new file mode 100644
index 0000000..84c8183
--- /dev/null
+++ b/aidl/tests/aidl_test_client.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+#include "aidl_test_client_file_descriptors.h"
+#include "aidl_test_client_nullables.h"
+#include "aidl_test_client_parcelables.h"
+#include "aidl_test_client_primitives.h"
+#include "aidl_test_client_service_exceptions.h"
+#include "aidl_test_client_utf8_strings.h"
+
+// libutils:
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::String16;
+
+// libbinder:
+using android::getService;
+
+// generated
+using android::aidl::tests::ITestService;
+
+using std::cerr;
+using std::cout;
+using std::endl;
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+const char kServiceName[] = "android.aidl.tests.ITestService";
+
+bool GetService(sp<ITestService>* service) {
+  cout << "Retrieving test service binder" << endl;
+  status_t status = getService(String16(kServiceName), service);
+  if (status != OK) {
+    cerr << "Failed to get service binder: '" << kServiceName
+         << "' status=" << status << endl;
+    return false;
+  }
+  return true;
+}
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+/* Runs all the test cases in aidl_test_client_*.cpp files. */
+int main(int /* argc */, char * argv []) {
+  android::base::InitLogging(argv, android::base::StderrLogger);
+  sp<ITestService> service;
+  namespace client_tests = android::aidl::tests::client;
+
+
+  if (!client_tests::GetService(&service)) return 1;
+
+  if (!client_tests::ConfirmPrimitiveRepeat(service)) return 1;
+
+  if (!client_tests::ConfirmReverseArrays(service)) return 1;
+
+  if (!client_tests::ConfirmReverseLists(service)) return 1;
+
+  if (!client_tests::ConfirmReverseBinderLists(service)) return 1;
+
+  if (!client_tests::ConfirmSimpleParcelables(service)) return 1;
+
+  if (!client_tests::ConfirmPersistableBundles(service)) return 1;
+
+  if (!client_tests::ConfirmFileDescriptors(service)) return 1;
+
+  if (!client_tests::ConfirmFileDescriptorArrays(service)) return 1;
+
+  if (!client_tests::ConfirmServiceSpecificExceptions(service)) return 1;
+
+  if (!client_tests::ConfirmNullables(service)) return 1;
+
+  if (!client_tests::ConfirmUtf8InCppStringRepeat(service)) return 1;
+
+  if (!client_tests::ConfirmUtf8InCppStringArrayReverse(service)) return 1;
+
+  if (!client_tests::ConfirmUtf8InCppStringListReverse(service)) return 1;
+
+  return 0;
+}
diff --git a/aidl/tests/aidl_test_client_file_descriptors.cpp b/aidl/tests/aidl_test_client_file_descriptors.cpp
new file mode 100644
index 0000000..b5913a3
--- /dev/null
+++ b/aidl/tests/aidl_test_client_file_descriptors.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl_test_client_file_descriptors.h"
+
+#include <iostream>
+#include <vector>
+
+ #include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <android-base/unique_fd.h>
+
+// libbase
+using android::base::unique_fd;
+
+// libutils:
+using android::sp;
+
+// libbinder:
+using android::binder::Status;
+
+// generated
+using android::aidl::tests::ITestService;
+
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::string;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+#define FdByName(_fd) #_fd, _fd
+
+bool DoWrite(const string& name, const unique_fd& fd, const string& buf) {
+  int wrote;
+
+  while ((wrote = write(fd.get(), buf.data(), buf.size())) < 0 && errno == EINTR);
+
+  if (wrote == (signed)buf.size()) {
+    return true;
+  }
+
+  if (wrote < 0) {
+    cerr << "Error writing to file descriptor '" << name << "': "
+        << strerror(errno) << endl;
+  } else {
+    cerr << "File descriptor '" << name << "'accepted short data." << endl;
+  }
+
+  return false;
+}
+
+bool DoRead(const string& name, const unique_fd& fd, const string& expected) {
+  size_t length = expected.size();
+  int got;
+  string buf;
+  buf.resize(length);
+
+  while ((got = read(fd.get(), &buf[0], length)) < 0 && errno == EINTR);
+
+  if (got < 0) {
+    cerr << "Error reading from '" << name << "': " << strerror(errno) << endl;
+    return false;
+  }
+
+  if (buf != expected) {
+    cerr << "Expected '" << expected << "' got '" << buf << "'" << endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool DoPipe(unique_fd* read_side, unique_fd* write_side) {
+  int fds[2];
+  unique_fd return_fd;
+
+  if (pipe(fds)) {
+    cout << "Error creating pipes: " << strerror(errno) << endl;
+    return false;
+  }
+
+  read_side->reset(fds[0]);
+  write_side->reset(fds[1]);
+  return true;
+}
+
+bool ConfirmFileDescriptors(const sp<ITestService>& s) {
+  Status status;
+  cout << "Confirming passing and returning file descriptors works." << endl;
+
+  unique_fd return_fd;
+  unique_fd read_fd;
+  unique_fd write_fd;
+
+  if (!DoPipe(&read_fd, &write_fd)) {
+    return false;
+  }
+
+  status = s->RepeatFileDescriptor(write_fd, &return_fd);
+
+  if (!status.isOk()) {
+    cerr << "Could not repeat file descriptors." << endl;
+    return false;
+  }
+
+  /* A note on some of the spookier stuff going on here: IIUC writes to pipes
+   * should be atomic and non-blocking so long as the total size doesn't exceed
+   * PIPE_BUF. We thus play a bit fast and loose with failure modes here.
+   */
+
+  bool ret =
+      DoWrite(FdByName(return_fd), "ReturnString") &&
+      DoRead(FdByName(read_fd), "ReturnString");
+
+  return ret;
+}
+
+bool ConfirmFileDescriptorArrays(const sp<ITestService>& s) {
+  Status status;
+  cout << "Confirming passing and returning file descriptor arrays works." << endl;
+
+  vector<unique_fd> array;
+  array.resize(2);
+
+  if (!DoPipe(&array[0], &array[1])) {
+    return false;
+  }
+
+  vector<unique_fd> repeated;
+  vector<unique_fd> reversed;
+
+  status = s->ReverseFileDescriptorArray(array, &repeated, &reversed);
+
+  if (!status.isOk()) {
+    cerr << "Could not reverse file descriptor array." << endl;
+    return false;
+  }
+
+  bool ret =
+      DoWrite(FdByName(array[1]), "First") &&
+      DoWrite(FdByName(repeated[1]), "Second") &&
+      DoWrite(FdByName(reversed[0]), "Third") &&
+      DoRead(FdByName(reversed[1]), "FirstSecondThird");
+
+  return ret;
+}
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/aidl_test_client_file_descriptors.h b/aidl/tests/aidl_test_client_file_descriptors.h
new file mode 100644
index 0000000..306e551
--- /dev/null
+++ b/aidl/tests/aidl_test_client_file_descriptors.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AIDL_TESTS_CLIENT_FILE_DESCRIPTORS_H
+#define ANDROID_AIDL_TESTS_CLIENT_FILE_DESCRIPTORS_H
+
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+// Tests for passing and returning file descriptors.
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmFileDescriptors(const sp<ITestService>& s);
+bool ConfirmFileDescriptorArrays(const sp<ITestService>& s);
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+#endif  // ANDROID_AIDL_TESTS_CLIENT_FILE_DESCRIPTORS_H
diff --git a/aidl/tests/aidl_test_client_nullables.cpp b/aidl/tests/aidl_test_client_nullables.cpp
new file mode 100644
index 0000000..805827c
--- /dev/null
+++ b/aidl/tests/aidl_test_client_nullables.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl_test_client_nullables.h"
+
+#include <utils/String16.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+// libutils:
+using android::sp;
+using android::String16;
+
+// libbinder:
+using android::binder::Status;
+
+// generated
+using android::aidl::tests::ITestService;
+using android::aidl::tests::SimpleParcelable;
+
+using std::string;
+using std::unique_ptr;
+using std::vector;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+namespace {
+template<typename T>
+bool ValuesEqual(const unique_ptr<T>& in, const unique_ptr<T>& out) {
+  return *in == *out;
+}
+
+template<>
+bool ValuesEqual<vector<unique_ptr<String16>>>(
+    const unique_ptr<vector<unique_ptr<String16>>>& in,
+    const unique_ptr<vector<unique_ptr<String16>>>& out) {
+  if (!in) {
+    return !out;
+  }
+
+  if (!out) {
+    return false;
+  }
+
+  if (in->size() != out->size()) {
+    return false;
+  }
+
+  for (size_t i = 0; i < in->size(); i++) {
+    const unique_ptr<String16>& a = (*in)[i];
+    const unique_ptr<String16>& b = (*out)[i];
+
+    if (!(a || b)) {
+      continue;
+    }
+
+    if (!(a && b)) {
+      return false;
+    }
+
+    if (*a != *b) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+template<typename T>
+bool ConfirmNullableType(const sp<ITestService>& s, const string& type_name,
+                         unique_ptr<T> in,
+                         Status(ITestService::*func)(const unique_ptr<T>&,
+                                                     unique_ptr<T>*)) {
+  cout << "... Confirming nullables for " << type_name << " ..." << endl;
+  Status status;
+  unique_ptr<T> out;
+
+  status = (*s.*func)(in, &out);
+
+  if (!status.isOk()) {
+    cerr << "Could not repeat nullable " << type_name << "." << endl;
+    return false;
+  }
+
+  if (!out) {
+    cerr << "Got back null when repeating " << type_name << "." << endl;
+    return false;
+  }
+
+  if (!ValuesEqual(in, out)) {
+    cerr << "Got back a non-matching value when repeating " << type_name
+         << "." << endl;
+    return false;
+  }
+
+  in.reset();
+  status = (*s.*func)(in, &out);
+
+  if (!status.isOk()) {
+    cerr << "Could not repeat null as " << type_name << "." << endl;
+    return false;
+  }
+
+  if (out) {
+    cerr << "Got back a value when sent null for " << type_name << "."
+         << endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool CheckAppropriateIBinderHandling(const sp<ITestService>& s) {
+
+  Status status;
+  sp<IBinder> binder = new BBinder();
+  sp<IBinder> null_binder = nullptr;
+  unique_ptr<vector<sp<IBinder>>> list_with_nulls(
+      new vector<sp<IBinder>>{binder, null_binder});
+  unique_ptr<vector<sp<IBinder>>> list_without_nulls(
+      new vector<sp<IBinder>>{binder, binder});
+
+  // Methods without @nullable throw up when given null binders
+  if (s->TakesAnIBinder(null_binder).exceptionCode() !=
+      binder::Status::EX_NULL_POINTER) {
+    cerr << "Did not receive expected null exception on line: "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (s->TakesAnIBinderList(*list_with_nulls).exceptionCode() !=
+      binder::Status::EX_NULL_POINTER) {
+    cerr << "Did not receive expected null exception on line: "
+         << __LINE__ << endl;
+    return false;
+  }
+
+  // But those same methods are fine with valid binders
+  if (!s->TakesAnIBinder(binder).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (!s->TakesAnIBinderList(*list_without_nulls).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+
+  // And methods with @nullable don't care.
+  if (!s->TakesANullableIBinder(null_binder).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (!s->TakesANullableIBinder(binder).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (!s->TakesANullableIBinderList(list_with_nulls).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (!s->TakesANullableIBinderList(list_without_nulls).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool CheckAppropriateIInterfaceHandling(const sp<ITestService>& s) {
+
+  sp<INamedCallback> callback;
+  if (!s->GetCallback(false, &callback).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (callback.get() == nullptr) {
+    cerr << "Expected to receive a non-null binder on line: "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (!s->GetCallback(true, &callback).isOk()) {
+    cerr << "Received unexpected exception on line "
+         << __LINE__ << endl;
+    return false;
+  }
+  if (callback.get() != nullptr) {
+    cerr << "Expected to receive a null binder on line: "
+         << __LINE__ << endl;
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+bool ConfirmNullables(const sp<ITestService>& s) {
+  Status status;
+  cout << "Confirming passing and returning nullable values works." << endl;
+
+  if (!ConfirmNullableType(s, "integer array",
+                           unique_ptr<vector<int32_t>>(
+                               new vector<int32_t>({1,2,3})),
+                           &ITestService::RepeatNullableIntArray)) {
+    return false;
+  }
+
+  if (!ConfirmNullableType(s, "string",
+                           unique_ptr<String16>(new String16("Blooob")),
+                           &ITestService::RepeatNullableString)) {
+    return false;
+  }
+
+  unique_ptr<vector<unique_ptr<String16>>> test_string_array(
+      new vector<unique_ptr<String16>>());
+  test_string_array->push_back(unique_ptr<String16>(new String16("Wat")));
+  test_string_array->push_back(unique_ptr<String16>(
+      new String16("Blooob")));
+  test_string_array->push_back(unique_ptr<String16>(new String16("Wat")));
+  test_string_array->push_back(unique_ptr<String16>(nullptr));
+  test_string_array->push_back(unique_ptr<String16>(new String16("YEAH")));
+  test_string_array->push_back(unique_ptr<String16>(
+      new String16("OKAAAAY")));
+
+  if (!ConfirmNullableType(s, "string array", std::move(test_string_array),
+                           &ITestService::RepeatNullableStringList)) {
+    return false;
+  }
+
+  if (!ConfirmNullableType(s, "parcelable",
+                           unique_ptr<SimpleParcelable>(
+                               new SimpleParcelable("Booya", 42)),
+                           &ITestService::RepeatNullableParcelable)) {
+    return false;
+  }
+
+  if (!CheckAppropriateIBinderHandling(s)) {
+    cerr << "Handled null IBinders poorly." << endl;
+    return false;
+  }
+
+  if (!CheckAppropriateIInterfaceHandling(s)) {
+    cerr << "Handled nullable IInterface instances poorly." << endl;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/aidl_test_client_nullables.h b/aidl/tests/aidl_test_client_nullables.h
new file mode 100644
index 0000000..807aa4e
--- /dev/null
+++ b/aidl/tests/aidl_test_client_nullables.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AIDL_TESTS_CLIENT_NULLABLES_H
+#define ANDROID_AIDL_TESTS_CLIENT_NULLABLES_H
+
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+// Tests for passing and returning file descriptors.
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmNullables(const sp<ITestService>& s);
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+#endif  // ANDROID_AIDL_TESTS_CLIENT_NULLABLES_H
diff --git a/aidl/tests/aidl_test_client_parcelables.cpp b/aidl/tests/aidl_test_client_parcelables.cpp
new file mode 100644
index 0000000..09e7f0a
--- /dev/null
+++ b/aidl/tests/aidl_test_client_parcelables.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl_test_client_parcelables.h"
+
+#include <iostream>
+#include <vector>
+
+// libutils:
+using android::sp;
+
+// libbinder:
+using android::binder::Status;
+
+// generated
+using android::aidl::tests::ITestService;
+using android::aidl::tests::SimpleParcelable;
+using android::os::PersistableBundle;
+
+using std::cout;
+using std::endl;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmSimpleParcelables(const sp<ITestService>& s) {
+  cout << "Confirming passing and returning SimpleParcelable objects works."
+       << endl;
+
+  SimpleParcelable input("Booya", 42);
+  SimpleParcelable out_param, returned;
+  Status status = s->RepeatSimpleParcelable(input, &out_param, &returned);
+  if (!status.isOk()) {
+    cout << "Binder call failed." << endl;
+    return false;
+  }
+  if (input != out_param || input != returned) {
+    cout << "Failed to repeat SimpleParcelable objects." << endl;
+    return false;
+  }
+
+  cout << "Attempting to reverse an array of SimpleParcelable objects." << endl;
+  const vector<SimpleParcelable> original{SimpleParcelable("first", 0),
+                                          SimpleParcelable("second", 1),
+                                          SimpleParcelable("third", 2)};
+  vector<SimpleParcelable> repeated;
+  vector<SimpleParcelable> reversed;
+  status = s->ReverseSimpleParcelables(original, &repeated, &reversed);
+  if (!status.isOk()) {
+    cout << "Binder call failed." << endl;
+    return false;
+  }
+  std::reverse(reversed.begin(), reversed.end());
+  if (repeated != original || reversed != original) {
+    cout << "Failed to reverse an array of SimpleParcelable objects." << endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool ConfirmPersistableBundles(const sp<ITestService>& s) {
+  cout << "Confirming passing and returning PersistableBundle objects works."
+       << endl;
+
+  PersistableBundle empty_bundle, returned;
+  Status status = s->RepeatPersistableBundle(empty_bundle, &returned);
+  if (!status.isOk()) {
+    cout << "Binder call failed for empty PersistableBundle." << endl;
+    return false;
+  }
+  if (empty_bundle != returned) {
+    cout << "Failed to repeat empty PersistableBundle." << endl;
+    return false;
+  }
+
+  PersistableBundle non_empty_bundle;
+  non_empty_bundle.putBoolean(String16("test_bool"), false);
+  non_empty_bundle.putInt(String16("test_int"), 33);
+  non_empty_bundle.putLong(String16("test_long"), 34359738368l);
+  non_empty_bundle.putDouble(String16("test_double"), 1.1);
+  non_empty_bundle.putString(String16("test_string"), String16("Woot!"));
+  non_empty_bundle.putBooleanVector(String16("test_bool_vector"),
+                                    {true, false, true});
+  non_empty_bundle.putIntVector(String16("test_int_vector"), {33, 44, 55, 142});
+  non_empty_bundle.putLongVector(String16("test_long_vector"),
+                                 {34l, 8371l, 34359738375l});
+  non_empty_bundle.putDoubleVector(String16("test_double_vector"), {2.2, 5.4});
+  non_empty_bundle.putStringVector(String16("test_string_vector"),
+                                   {String16("hello"), String16("world!")});
+  PersistableBundle nested_bundle;
+  nested_bundle.putInt(String16("test_nested_int"), 345);
+  non_empty_bundle.putPersistableBundle(String16("test_persistable_bundle"),
+                                        nested_bundle);
+
+  status = s->RepeatPersistableBundle(non_empty_bundle, &returned);
+  if (!status.isOk()) {
+    cout << "Binder call failed. " << endl;
+    return false;
+  }
+  if (non_empty_bundle != returned) {
+    cout << "Failed to repeat PersistableBundle object." << endl;
+    return false;
+  }
+
+  cout << "Attempting to reverse an array of PersistableBundle objects."
+       << endl;
+  PersistableBundle first;
+  PersistableBundle second;
+  PersistableBundle third;
+  first.putInt(String16("test_int"), 1231);
+  second.putLong(String16("test_long"), 222222l);
+  third.putDouble(String16("test_double"), 10.8);
+  const vector<PersistableBundle> original{first, second, third};
+
+  vector<PersistableBundle> repeated;
+  vector<PersistableBundle> reversed;
+  status = s->ReversePersistableBundles(original, &repeated, &reversed);
+  if (!status.isOk()) {
+    cout << "Binder call failed." << endl;
+    return false;
+  }
+  std::reverse(reversed.begin(), reversed.end());
+  if (repeated != original || reversed != original) {
+    cout << "Failed to reverse an array of PersistableBundle objects." << endl;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/aidl_test_client_parcelables.h b/aidl/tests/aidl_test_client_parcelables.h
new file mode 100644
index 0000000..9616e02
--- /dev/null
+++ b/aidl/tests/aidl_test_client_parcelables.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AIDL_TESTS_CLIENT_PARCELABLES_H
+#define ANDROID_AIDL_TESTS_CLIENT_PARCELABLES_H
+
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+// Tests for passing and returning parcelable types.
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmSimpleParcelables(const sp<ITestService>& s);
+bool ConfirmPersistableBundles(const sp<ITestService>& s);
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+#endif  // ANDROID_AIDL_TESTS_CLIENT_PARCELABLES_H
diff --git a/aidl/tests/aidl_test_client_primitives.cpp b/aidl/tests/aidl_test_client_primitives.cpp
new file mode 100644
index 0000000..6f70f43
--- /dev/null
+++ b/aidl/tests/aidl_test_client_primitives.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl_test_client_primitives.h"
+
+#include <iostream>
+#include <vector>
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include "android/aidl/tests/INamedCallback.h"
+
+#include "test_helpers.h"
+
+// libutils:
+using android::sp;
+using android::String16;
+using android::String8;
+
+// libbinder:
+using android::binder::Status;
+
+// generated
+using android::aidl::tests::ITestService;
+using android::aidl::tests::INamedCallback;
+
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmPrimitiveRepeat(const sp<ITestService>& s) {
+  cout << "Confirming passing and returning primitives works." << endl;
+
+  if (!RepeatPrimitive(s, &ITestService::RepeatBoolean, true) ||
+      !RepeatPrimitive(s, &ITestService::RepeatByte, int8_t{-128}) ||
+      !RepeatPrimitive(s, &ITestService::RepeatChar, char16_t{'A'}) ||
+      !RepeatPrimitive(s, &ITestService::RepeatInt, int32_t{1 << 30}) ||
+      !RepeatPrimitive(s, &ITestService::RepeatLong, int64_t{1ll << 60}) ||
+      !RepeatPrimitive(s, &ITestService::RepeatFloat, float{1.0f/3.0f}) ||
+      !RepeatPrimitive(s, &ITestService::RepeatDouble, double{1.0/3.0}) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT)  ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT2) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT3) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT4) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT5) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT6) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT7) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT8) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT9) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT10) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT11) ||
+      !RepeatPrimitive(
+          s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT12)
+      ) {
+    return false;
+  }
+
+  vector<String16> inputs = {
+      String16("Deliver us from evil."),
+      String16(),
+      String16("\0\0", 2),
+      // This is actually two unicode code points:
+      //   U+10437: The 'small letter yee' character in the deseret alphabet
+      //   U+20AC: A euro sign
+      String16("\xD8\x01\xDC\x37\x20\xAC"),
+      ITestService::STRING_TEST_CONSTANT(),
+      ITestService::STRING_TEST_CONSTANT2(),
+  };
+  for (const auto& input : inputs) {
+    String16 reply;
+    Status status = s->RepeatString(input, &reply);
+    if (!status.isOk() || input != reply) {
+      cerr << "Failed while requesting service to repeat String16=\""
+           << String8(input).string()
+           << "\". Got status=" << status.toString8() << endl;
+      return false;
+    }
+  }
+  return true;
+}
+
+bool ConfirmReverseArrays(const sp<ITestService>& s) {
+  cout << "Confirming passing and returning arrays works." << endl;
+
+  if (!ReverseArray(s, &ITestService::ReverseBoolean,
+                    {true, false, false}) ||
+      !ReverseArray(s, &ITestService::ReverseByte,
+                    {uint8_t{255}, uint8_t{0}, uint8_t{127}}) ||
+      !ReverseArray(s, &ITestService::ReverseChar,
+                    {char16_t{'A'}, char16_t{'B'}, char16_t{'C'}}) ||
+      !ReverseArray(s, &ITestService::ReverseInt,
+                    {1, 2, 3}) ||
+      !ReverseArray(s, &ITestService::ReverseLong,
+                    {-1ll, 0ll, int64_t{1ll << 60}}) ||
+      !ReverseArray(s, &ITestService::ReverseFloat,
+                    {-0.3f, -0.7f, 8.0f}) ||
+      !ReverseArray(s, &ITestService::ReverseDouble,
+                    {1.0/3.0, 1.0/7.0, 42.0}) ||
+      !ReverseArray(s, &ITestService::ReverseString,
+                    {String16{"f"}, String16{"a"}, String16{"b"}})) {
+    return false;
+  }
+
+  return true;
+}
+
+bool ConfirmReverseLists(const sp<ITestService>& s) {
+  cout << "Confirming passing and returning List<T> works." << endl;
+
+  if (!ReverseArray(s, &ITestService::ReverseStringList,
+                    {String16{"f"}, String16{"a"}, String16{"b"}})) {
+    return false;
+  }
+
+  return true;
+}
+
+bool ConfirmReverseBinderLists(const sp<ITestService>& s) {
+  Status status;
+  cout << "Confirming passing and returning List<T> works with binders." << endl;
+
+  vector<String16> names = {
+    String16{"Larry"},
+    String16{"Curly"},
+    String16{"Moe"}
+  };
+
+  vector<sp<IBinder>> input;
+
+  for (int i = 0; i < 3; i++) {
+    sp<INamedCallback> got;
+
+    status = s->GetOtherTestService(names[i], &got);
+    if (!status.isOk()) {
+      cerr << "Could not retrieve service for test." << endl;
+      return false;
+    }
+
+    input.push_back(INamedCallback::asBinder(got));
+  }
+
+  vector<sp<IBinder>> output;
+  vector<sp<IBinder>> reversed;
+
+  status = s->ReverseNamedCallbackList(input, &output, &reversed);
+  if (!status.isOk()) {
+    cerr << "Failed to reverse named callback list." << endl;
+  }
+
+  if (output.size() != 3) {
+    cerr << "ReverseNamedCallbackList gave repetition with wrong length." << endl;
+    return false;
+  }
+
+  if (reversed.size() != 3) {
+    cerr << "ReverseNamedCallbackList gave reversal with wrong length." << endl;
+    return false;
+  }
+
+  for (int i = 0; i < 3; i++) {
+    String16 ret;
+    sp<INamedCallback> named_callback =
+        android::interface_cast<INamedCallback>(output[i]);
+    status = named_callback->GetName(&ret);
+
+    if (!status.isOk()) {
+      cerr << "Could not query INamedCallback from output" << endl;
+      return false;
+    }
+
+    if (ret != names[i]) {
+      cerr << "Output had wrong INamedCallback" << endl;
+      return false;
+    }
+  }
+
+  for (int i = 0; i < 3; i++) {
+    String16 ret;
+    sp<INamedCallback> named_callback =
+        android::interface_cast<INamedCallback>(reversed[i]);
+    status = named_callback->GetName(&ret);
+
+    if (!status.isOk()) {
+      cerr << "Could not query INamedCallback from reversed output" << endl;
+      return false;
+    }
+
+    if (ret != names[2 - i]) {
+      cerr << "Reversed output had wrong INamedCallback" << endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/aidl_test_client_primitives.h b/aidl/tests/aidl_test_client_primitives.h
new file mode 100644
index 0000000..f9b39da
--- /dev/null
+++ b/aidl/tests/aidl_test_client_primitives.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AIDL_TESTS_CLIENT_PRIMITIVES_H
+#define ANDROID_AIDL_TESTS_CLIENT_PRIMITIVES_H
+
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+// Tests for passing and returning primitive types defined in the AIDL docs.
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmPrimitiveRepeat(const sp<ITestService>& s);
+bool ConfirmReverseArrays(const android::sp<ITestService>& s);
+bool ConfirmReverseLists(const android::sp<ITestService>& s);
+bool ConfirmReverseBinderLists(const android::sp<ITestService>& s);
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+#endif  // ANDROID_AIDL_TESTS_CLIENT_PRIMITIVES_H
diff --git a/aidl/tests/aidl_test_client_service_exceptions.cpp b/aidl/tests/aidl_test_client_service_exceptions.cpp
new file mode 100644
index 0000000..3f1f374
--- /dev/null
+++ b/aidl/tests/aidl_test_client_service_exceptions.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl_test_client_service_exceptions.h"
+
+#include <iostream>
+
+#include "binder/Status.h"
+
+using android::binder::Status;
+using std::cout;
+using std::endl;
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmServiceSpecificExceptions(const sp<ITestService>& s) {
+  cout << "Confirming application exceptions work" << endl;
+
+  for (int32_t i = -1; i < 2; ++i) {
+    Status status = s->ThrowServiceException(i);
+    if (status.exceptionCode() != Status::EX_SERVICE_SPECIFIC ||
+        status.serviceSpecificErrorCode() != i) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/aidl_test_client_service_exceptions.h b/aidl/tests/aidl_test_client_service_exceptions.h
new file mode 100644
index 0000000..e4a1dd3
--- /dev/null
+++ b/aidl/tests/aidl_test_client_service_exceptions.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AIDL_TESTS_CLIENT_SERVICE_EXCEPTIONS_H
+#define ANDROID_AIDL_TESTS_CLIENT_SERVICE_EXCEPTIONS_H
+
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+// Tests for service specific exception support.
+bool ConfirmServiceSpecificExceptions(const sp<ITestService>& s);
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+#endif  // ANDROID_AIDL_TESTS_CLIENT_SERVICE_EXCEPTIONS_H
diff --git a/aidl/tests/aidl_test_client_utf8_strings.cpp b/aidl/tests/aidl_test_client_utf8_strings.cpp
new file mode 100644
index 0000000..216aef7
--- /dev/null
+++ b/aidl/tests/aidl_test_client_utf8_strings.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl_test_client_utf8_strings.h"
+
+#include <android-base/logging.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "android/aidl/tests/ITestService.h"
+#include "test_helpers.h"
+
+// libutils:
+using android::sp;
+
+// libbinder:
+using android::binder::Status;
+
+// generated
+using android::aidl::tests::ITestService;
+
+using std::unique_ptr;
+using std::string;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmUtf8InCppStringRepeat(const sp<ITestService>& s) {
+  const vector<string> utf8_inputs = {
+    string("Deliver us from evil."),
+    string(),
+    string("\0\0", 2),
+    // Similarly, the utf8 encodings of the small letter yee and euro sign.
+    string("\xF0\x90\x90\xB7\xE2\x82\xAC"),
+  };
+  LOG(INFO) << "Confirming repeating utf8 strings works.";
+
+  for (const auto& input : utf8_inputs) {
+    string reply;
+    Status status = s->RepeatUtf8CppString(input, &reply);
+    if (!status.isOk() || input != reply) {
+      LOG(ERROR) << "Failed while requesting service to repeat utf8 string=\""
+                 << input
+                 << "\". Got status=" << status.toString8()
+                 << " and output=" << reply;
+      return false;
+    }
+  }
+
+  unique_ptr<string> ret;
+  Status repeat_null_status = s->RepeatNullableUtf8CppString(nullptr, &ret);
+  if (!repeat_null_status.isOk() || ret) {
+    LOG(ERROR) << "RepeatNullableUtf8CppString(null) did not return null";
+    return false;
+  }
+
+  for (const auto& input : utf8_inputs) {
+    unique_ptr<string> reply;
+    Status status = s->RepeatNullableUtf8CppString(
+        unique_ptr<string>(new string(input)), &reply);
+    if (!status.isOk()) {
+      LOG(ERROR) << "Got status=" << status.toString8() << " while repeating "
+                    "nullable utf8 string " << input;
+      return false;
+    }
+    if (!reply) {
+      LOG(ERROR) << "Got null reply while repeating nullable utf8 string "
+                 << input;
+      return false;
+    }
+    if (input != *reply) {
+      LOG(ERROR) << "Failed while requesting service to repeat utf8 string=\""
+                 << input
+                 << "\". Got status=" << status.toString8()
+                 << " and output=" << *reply;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool ConfirmUtf8InCppStringArrayReverse(const sp<ITestService>& s) {
+  LOG(INFO) << "Confirming passing and returning utf8 string arrays works.";
+  if (!ReverseArray(s, &ITestService::ReverseUtf8CppString,
+                    {string{"a"}, string{}, string{"\xc3\xb8"}})) {
+    return false;
+  }
+
+  return true;
+}
+
+bool ConfirmUtf8InCppStringListReverse(const sp<ITestService>& s) {
+  LOG(INFO) << "Confirming reversing a list of utf8 strings works";
+  unique_ptr<vector<unique_ptr<string>>> input, reversed, repeated;
+  Status status = s->ReverseUtf8CppStringList(input, &reversed, &repeated);
+  if (!status.isOk() || reversed || repeated) {
+    LOG(ERROR) << "Reversing null list of utf8 strings failed.";
+    return false;
+  }
+
+  input.reset(new vector<unique_ptr<string>>);
+  input->emplace_back(new string("Deliver us from evil."));
+  input->emplace_back(nullptr);
+  input->emplace_back(new string("\xF0\x90\x90\xB7\xE2\x82\xAC"));
+
+  status = s->ReverseUtf8CppStringList(input, &repeated, &reversed);
+  if (!status.isOk() || !reversed || !repeated) {
+    LOG(ERROR) << "Reversing list of utf8 strings failed.";
+    return false;
+  }
+  if (reversed->size() != input->size() || repeated->size() != input->size()) {
+    LOG(ERROR) << "Bad output sizes.";
+    return false;
+  }
+
+  for (size_t i = 0; i < input->size(); ++i) {
+    const string* input_str = (*input)[i].get();
+    const string* repeated_str = (*repeated)[i].get();
+    const string* reversed_str = (*reversed)[(reversed->size() - 1) - i].get();
+    if (!input_str) {
+      if(repeated_str || reversed_str) {
+        LOG(ERROR) << "Expected null values, but got non-null.";
+        return false;
+      }
+      // 3 nullptrs to strings.  No need to compare values.
+      continue;
+    }
+    if (!repeated_str || !reversed_str) {
+      LOG(ERROR) << "Expected non-null values, but got null.";
+      return false;
+    }
+    if (*input_str != *repeated_str || *input_str != *reversed_str) {
+      LOG(ERROR) << "Expected '" << *input_str << "' but got "
+                 << "repeated='" << *repeated_str << "' and "
+                 << "reversed='" << *reversed_str;
+      return false;
+    }
+  }
+  return true;
+}
+
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/aidl_test_client_utf8_strings.h b/aidl/tests/aidl_test_client_utf8_strings.h
new file mode 100644
index 0000000..a362fd5
--- /dev/null
+++ b/aidl/tests/aidl_test_client_utf8_strings.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AIDL_TESTS_CLIENT_UTF8_STRINGS_H
+#define ANDROID_AIDL_TESTS_CLIENT_UTF8_STRINGS_H
+
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+// Tests for passing and returning utf8 strings.
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+bool ConfirmUtf8InCppStringRepeat(
+    const android::sp<android::aidl::tests::ITestService>& s);
+bool ConfirmUtf8InCppStringArrayReverse(
+    const android::sp<android::aidl::tests::ITestService>& s);
+bool ConfirmUtf8InCppStringListReverse(
+    const android::sp<android::aidl::tests::ITestService>& s);
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+#endif  // ANDROID_AIDL_TESTS_CLIENT_UTF8_STRINGS_H
+
diff --git a/aidl/tests/aidl_test_sentinel_searcher.cpp b/aidl/tests/aidl_test_sentinel_searcher.cpp
new file mode 100644
index 0000000..e260366
--- /dev/null
+++ b/aidl/tests/aidl_test_sentinel_searcher.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::getline;
+using std::ifstream;
+using std::string;
+using std::vector;
+
+namespace {
+
+bool ReadLines(const string& input_file_path, vector<string>* lines) {
+  ifstream watched_file(input_file_path);
+  if (!watched_file.is_open()) {
+    cerr << "Unable to open input file: " << input_file_path << endl;
+    return false;
+  }
+
+  string line;
+  while (getline(watched_file, line)) {
+    lines->push_back(line);
+  }
+  watched_file.close();
+  return true;
+}
+
+bool HasSentinel(const vector<string>& lines, const string& sentinel) {
+  for (const auto& line : lines) {
+    if (line.find(sentinel) != string::npos) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+int main(int argc, const char* argv[]) {
+  if (argc != 5) {
+    cerr << "Invalid usage." << endl;
+    cerr << argv[0]
+         << " <timeout in seconds>"
+         << " <input file path>"
+         << " <success sentinel>"
+         << " <failure sentinel>" << endl;
+    return -EINVAL;
+  }
+  const string timeout_as_str = argv[1];
+  const string input_file_path = argv[2];
+  const string success_sentinel = argv[3];
+  const string failure_sentinel = argv[4];
+
+  const int timeout_seconds = atoi(timeout_as_str.c_str());
+  if (timeout_seconds <= 0) {
+    cerr << "Invalid timeout value (in seconds): " << timeout_as_str << endl;
+    return -EINVAL;
+  }
+
+  int exit_code = 1;
+  const time_t start_time = time(nullptr);
+  vector<string> lines;
+  while (true) {
+    sleep(1);
+    if (time(nullptr) - start_time > timeout_seconds) {
+      cerr << "Timed out waiting for success/failure sentinel." << endl;
+      break;
+    }
+    // Ignore errors when reading lines.  The file may not immediately exist
+    // because it takes the Java process some time to create it.
+    lines.clear();
+    ReadLines(input_file_path, &lines);
+
+    if (HasSentinel(lines, success_sentinel)) {
+      exit_code = 0;
+      break;
+    }
+    if (HasSentinel(lines, failure_sentinel)) {
+      break;
+    }
+  }
+
+  cout << "Found output:" << endl;
+  for (const auto& line : lines) {
+    cout << "  " << line << endl;
+  }
+  return exit_code;
+}
diff --git a/aidl/tests/aidl_test_service.cpp b/aidl/tests/aidl_test_service.cpp
new file mode 100644
index 0000000..9e2304e
--- /dev/null
+++ b/aidl/tests/aidl_test_service.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <unistd.h>
+
+#include <android-base/unique_fd.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Status.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/BnTestService.h"
+#include "android/aidl/tests/ITestService.h"
+
+#include "android/aidl/tests/BnNamedCallback.h"
+#include "android/aidl/tests/INamedCallback.h"
+
+// Used implicitly.
+#undef LOG_TAG
+#define LOG_TAG "aidl_native_service"
+
+// libbase
+using android::base::unique_fd;
+
+// libutils:
+using android::Looper;
+using android::LooperCallback;
+using android::OK;
+using android::sp;
+using android::String16;
+
+// libbinder:
+using android::BnInterface;
+using android::defaultServiceManager;
+using android::IInterface;
+using android::IPCThreadState;
+using android::Parcel;
+using android::ProcessState;
+using android::binder::Status;
+
+// Generated code:
+using android::aidl::tests::BnNamedCallback;
+using android::aidl::tests::BnTestService;
+using android::aidl::tests::INamedCallback;
+using android::aidl::tests::SimpleParcelable;
+using android::os::PersistableBundle;
+
+// Standard library
+using std::map;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace {
+
+class BinderCallback : public LooperCallback {
+ public:
+  BinderCallback() {}
+  ~BinderCallback() override {}
+
+  int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
+    IPCThreadState::self()->handlePolledCommands();
+    return 1;  // Continue receiving callbacks.
+  }
+};
+
+class NamedCallback : public BnNamedCallback {
+ public:
+  explicit NamedCallback(String16 name) : name_(name) {}
+
+  Status GetName(String16* ret) {
+    *ret = name_;
+    return Status::ok();
+  }
+
+ private:
+  String16 name_;
+};
+
+class NativeService : public BnTestService {
+ public:
+  NativeService() {}
+  virtual ~NativeService() = default;
+
+  void LogRepeatedStringToken(const String16& token) {
+    ALOGI("Repeating '%s' of length=%zu", android::String8(token).string(),
+          token.size());
+  }
+
+  template <typename T>
+  void LogRepeatedToken(const T& token) {
+    std::ostringstream token_str;
+    token_str << token;
+    ALOGI("Repeating token %s", token_str.str().c_str());
+  }
+
+  Status RepeatBoolean(bool token, bool* _aidl_return) override {
+    LogRepeatedToken(token ? 1 : 0);
+    *_aidl_return = token;
+    return Status::ok();
+  }
+  Status RepeatByte(int8_t token, int8_t* _aidl_return) override {
+    LogRepeatedToken(token);
+    *_aidl_return = token;
+    return Status::ok();
+  }
+  Status RepeatChar(char16_t token, char16_t* _aidl_return) override {
+    LogRepeatedStringToken(String16(&token, 1));
+    *_aidl_return = token;
+    return Status::ok();
+  }
+  Status RepeatInt(int32_t token, int32_t* _aidl_return) override {
+    LogRepeatedToken(token);
+    *_aidl_return = token;
+    return Status::ok();
+  }
+  Status RepeatLong(int64_t token, int64_t* _aidl_return) override {
+    LogRepeatedToken(token);
+    *_aidl_return = token;
+    return Status::ok();
+  }
+  Status RepeatFloat(float token, float* _aidl_return) override {
+    LogRepeatedToken(token);
+    *_aidl_return = token;
+    return Status::ok();
+  }
+  Status RepeatDouble(double token, double* _aidl_return) override {
+    LogRepeatedToken(token);
+    *_aidl_return = token;
+    return Status::ok();
+  }
+  Status RepeatString(const String16& token, String16* _aidl_return) override {
+    LogRepeatedStringToken(token);
+    *_aidl_return = token;
+    return Status::ok();
+  }
+
+  Status RepeatSimpleParcelable(const SimpleParcelable& input,
+                                SimpleParcelable* repeat,
+                                SimpleParcelable* _aidl_return) override {
+    ALOGI("Repeated a SimpleParcelable %s", input.toString().c_str());
+    *repeat = input;
+    *_aidl_return = input;
+    return Status::ok();
+  }
+
+  Status RepeatPersistableBundle(const PersistableBundle& input,
+                                 PersistableBundle* _aidl_return) override {
+    ALOGI("Repeated a PersistableBundle");
+    *_aidl_return = input;
+    return Status::ok();
+  }
+
+  template <typename T>
+  Status ReverseArray(const vector<T>& input, vector<T>* repeated,
+                      vector<T>* _aidl_return) {
+    ALOGI("Reversing array of length %zu", input.size());
+    *repeated = input;
+    *_aidl_return = input;
+    std::reverse(_aidl_return->begin(), _aidl_return->end());
+    return Status::ok();
+  }
+
+  template<typename T>
+  Status RepeatNullable(const unique_ptr<T>& input,
+                        unique_ptr<T>* _aidl_return) {
+    ALOGI("Repeating nullable value");
+
+    _aidl_return->reset();
+    if (input) {
+      _aidl_return->reset(new T(*input));
+    }
+
+    return Status::ok();
+  }
+
+  Status ReverseBoolean(const vector<bool>& input,
+                        vector<bool>* repeated,
+                        vector<bool>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseByte(const vector<uint8_t>& input,
+                     vector<uint8_t>* repeated,
+                     vector<uint8_t>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseChar(const vector<char16_t>& input,
+                     vector<char16_t>* repeated,
+                     vector<char16_t>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseInt(const vector<int32_t>& input,
+                    vector<int32_t>* repeated,
+                    vector<int32_t>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseLong(const vector<int64_t>& input,
+                     vector<int64_t>* repeated,
+                     vector<int64_t>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseFloat(const vector<float>& input,
+                      vector<float>* repeated,
+                      vector<float>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseDouble(const vector<double>& input,
+                       vector<double>* repeated,
+                       vector<double>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseString(const vector<String16>& input,
+                       vector<String16>* repeated,
+                       vector<String16>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReverseSimpleParcelables(
+      const vector<SimpleParcelable>& input,
+      vector<SimpleParcelable>* repeated,
+      vector<SimpleParcelable>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+  Status ReversePersistableBundles(
+      const vector<PersistableBundle>& input,
+      vector<PersistableBundle>* repeated,
+      vector<PersistableBundle>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+
+  Status GetOtherTestService(const String16& name,
+                             sp<INamedCallback>* returned_service) override {
+    if (service_map_.find(name) == service_map_.end()) {
+      sp<INamedCallback> new_item(new NamedCallback(name));
+      service_map_[name] = new_item;
+    }
+
+    *returned_service = service_map_[name];
+    return Status::ok();
+  }
+
+  Status VerifyName(const sp<INamedCallback>& service, const String16& name,
+                    bool* returned_value) override {
+    String16 foundName;
+    Status status = service->GetName(&foundName);
+
+    if (status.isOk()) {
+      *returned_value = foundName == name;
+    }
+
+    return status;
+  }
+
+  Status ReverseStringList(const vector<String16>& input,
+                           vector<String16>* repeated,
+                           vector<String16>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+
+  Status ReverseNamedCallbackList(const vector<sp<IBinder>>& input,
+                                  vector<sp<IBinder>>* repeated,
+                                  vector<sp<IBinder>>* _aidl_return) override {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+
+  Status RepeatFileDescriptor(const unique_fd& read,
+                              unique_fd* _aidl_return) override {
+    ALOGE("Repeating file descriptor");
+    *_aidl_return = unique_fd(dup(read.get()));
+    return Status::ok();
+  }
+
+  Status ReverseFileDescriptorArray(const vector<unique_fd>& input,
+                                    vector<unique_fd>* repeated,
+                                    vector<unique_fd>* _aidl_return) override {
+    ALOGI("Reversing descriptor array of length %zu", input.size());
+    for (const auto& item : input) {
+      repeated->push_back(unique_fd(dup(item.get())));
+      _aidl_return->push_back(unique_fd(dup(item.get())));
+    }
+    std::reverse(_aidl_return->begin(), _aidl_return->end());
+    return Status::ok();
+  }
+
+  Status ThrowServiceException(int code) override {
+    return Status::fromServiceSpecificError(code);
+  }
+
+  Status RepeatNullableIntArray(const unique_ptr<vector<int32_t>>& input,
+                                unique_ptr<vector<int32_t>>* _aidl_return) {
+    return RepeatNullable(input, _aidl_return);
+  }
+
+  Status RepeatNullableStringList(
+             const unique_ptr<vector<unique_ptr<String16>>>& input,
+             unique_ptr<vector<unique_ptr<String16>>>* _aidl_return) {
+    ALOGI("Repeating nullable string list");
+    if (!input) {
+      _aidl_return->reset();
+      return Status::ok();
+    }
+
+    _aidl_return->reset(new vector<unique_ptr<String16>>);
+
+    for (const auto& item : *input) {
+      if (!item) {
+        (*_aidl_return)->emplace_back(nullptr);
+      } else {
+        (*_aidl_return)->emplace_back(new String16(*item));
+      }
+    }
+
+    return Status::ok();
+  }
+
+  Status RepeatNullableString(const unique_ptr<String16>& input,
+                              unique_ptr<String16>* _aidl_return) {
+    return RepeatNullable(input, _aidl_return);
+  }
+
+  Status RepeatNullableParcelable(const unique_ptr<SimpleParcelable>& input,
+                              unique_ptr<SimpleParcelable>* _aidl_return) {
+    return RepeatNullable(input, _aidl_return);
+  }
+
+  Status TakesAnIBinder(const sp<IBinder>& input) override {
+    (void)input;
+    return Status::ok();
+  }
+  Status TakesAnIBinderList(const vector<sp<IBinder>>& input) override {
+    (void)input;
+    return Status::ok();
+  }
+  Status TakesANullableIBinder(const sp<IBinder>& input) {
+    (void)input;
+    return Status::ok();
+  }
+  Status TakesANullableIBinderList(const unique_ptr<vector<sp<IBinder>>>& input) {
+    (void)input;
+    return Status::ok();
+  }
+
+  Status RepeatUtf8CppString(const string& token,
+                             string* _aidl_return) override {
+    ALOGI("Repeating utf8 string '%s' of length=%zu", token.c_str(), token.size());
+    *_aidl_return = token;
+    return Status::ok();
+  }
+
+  Status RepeatNullableUtf8CppString(
+      const unique_ptr<string>& token,
+      unique_ptr<string>* _aidl_return) override {
+    if (!token) {
+      ALOGI("Received null @utf8InCpp string");
+      return Status::ok();
+    }
+    ALOGI("Repeating utf8 string '%s' of length=%zu",
+          token->c_str(), token->size());
+    _aidl_return->reset(new string(*token));
+    return Status::ok();
+  }
+
+  Status ReverseUtf8CppString(const vector<string>& input,
+                              vector<string>* repeated,
+                              vector<string>* _aidl_return) {
+    return ReverseArray(input, repeated, _aidl_return);
+  }
+
+  Status ReverseUtf8CppStringList(
+      const unique_ptr<vector<unique_ptr<::string>>>& input,
+      unique_ptr<vector<unique_ptr<string>>>* repeated,
+      unique_ptr<vector<unique_ptr<string>>>* _aidl_return) {
+    if (!input) {
+      ALOGI("Received null list of utf8 strings");
+      return Status::ok();
+    }
+    _aidl_return->reset(new vector<unique_ptr<string>>);
+    repeated->reset(new vector<unique_ptr<string>>);
+
+    for (const auto& item : *input) {
+      (*repeated)->emplace_back(nullptr);
+      (*_aidl_return)->emplace_back(nullptr);
+      if (item) {
+        (*repeated)->back().reset(new string(*item));
+        (*_aidl_return)->back().reset(new string(*item));
+      }
+    }
+    std::reverse((*_aidl_return)->begin(), (*_aidl_return)->end());
+
+    return Status::ok();
+  }
+
+  Status GetCallback(bool return_null, sp<INamedCallback>* ret) {
+    if (!return_null) {
+      return GetOtherTestService(String16("ABT: always be testing"), ret);
+    }
+    return Status::ok();
+  }
+
+ private:
+  map<String16, sp<INamedCallback>> service_map_;
+};
+
+int Run() {
+  android::sp<NativeService> service = new NativeService;
+  sp<Looper> looper(Looper::prepare(0 /* opts */));
+
+  int binder_fd = -1;
+  ProcessState::self()->setThreadPoolMaxThreadCount(0);
+  IPCThreadState::self()->disableBackgroundScheduling(true);
+  IPCThreadState::self()->setupPolling(&binder_fd);
+  ALOGI("Got binder FD %d", binder_fd);
+  if (binder_fd < 0) return -1;
+
+  sp<BinderCallback> cb(new BinderCallback);
+  if (looper->addFd(binder_fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb,
+                    nullptr) != 1) {
+    ALOGE("Failed to add binder FD to Looper");
+    return -1;
+  }
+
+  defaultServiceManager()->addService(service->getInterfaceDescriptor(),
+                                      service);
+
+  ALOGI("Entering loop");
+  while (true) {
+    const int result = looper->pollAll(-1 /* timeoutMillis */);
+    ALOGI("Looper returned %d", result);
+  }
+  return 0;
+}
+
+}  // namespace
+
+int main(int /* argc */, char* /* argv */ []) {
+  return Run();
+}
diff --git a/aidl/tests/android/aidl/tests/INamedCallback.aidl b/aidl/tests/android/aidl/tests/INamedCallback.aidl
new file mode 100644
index 0000000..c295fef
--- /dev/null
+++ b/aidl/tests/android/aidl/tests/INamedCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+interface INamedCallback {
+  String GetName();
+}
diff --git a/aidl/tests/android/aidl/tests/ITestService.aidl b/aidl/tests/android/aidl/tests/ITestService.aidl
new file mode 100644
index 0000000..4de6925
--- /dev/null
+++ b/aidl/tests/android/aidl/tests/ITestService.aidl
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+import android.aidl.tests.INamedCallback;
+import android.aidl.tests.SimpleParcelable;
+import android.os.PersistableBundle;
+
+interface ITestService {
+  // Test that constants are accessible
+  const int TEST_CONSTANT = 42;
+  const int TEST_CONSTANT2 = -42;
+  const int TEST_CONSTANT3 = +42;
+  const int TEST_CONSTANT4 = +4;
+  const int TEST_CONSTANT5 = -4;
+  const int TEST_CONSTANT6 = -0;
+  const int TEST_CONSTANT7 = +0;
+  const int TEST_CONSTANT8 = 0;
+  const int TEST_CONSTANT9 = 0x56;
+  const int TEST_CONSTANT10 = 0xa5;
+  const int TEST_CONSTANT11 = 0xFA;
+  const int TEST_CONSTANT12 = 0xffffffff;
+
+  const String STRING_TEST_CONSTANT = "foo";
+  const String STRING_TEST_CONSTANT2 = "bar";
+
+  // Test that primitives work as parameters and return types.
+  boolean RepeatBoolean(boolean token);
+  byte RepeatByte(byte token);
+  char RepeatChar(char token);
+  int RepeatInt(int token);
+  long RepeatLong(long token);
+  float RepeatFloat(float token);
+  double RepeatDouble(double token);
+  String RepeatString(String token);
+
+  SimpleParcelable RepeatSimpleParcelable(in SimpleParcelable input,
+                                          out SimpleParcelable repeat);
+  PersistableBundle RepeatPersistableBundle(in PersistableBundle input);
+
+  // Test that arrays work as parameters and return types.
+  boolean[] ReverseBoolean(in boolean[] input, out boolean[] repeated);
+  byte[]    ReverseByte   (in byte[]    input, out byte[]    repeated);
+  char[]    ReverseChar   (in char[]    input, out char[]    repeated);
+  int[]     ReverseInt    (in int[]     input, out int[]     repeated);
+  long[]    ReverseLong   (in long[]    input, out long[]    repeated);
+  float[]   ReverseFloat  (in float[]   input, out float[]   repeated);
+  double[]  ReverseDouble (in double[]  input, out double[]  repeated);
+  String[]  ReverseString (in String[]  input, out String[]  repeated);
+
+  SimpleParcelable[]  ReverseSimpleParcelables(in SimpleParcelable[] input,
+                                               out SimpleParcelable[] repeated);
+  PersistableBundle[] ReversePersistableBundles(
+      in PersistableBundle[] input, out PersistableBundle[] repeated);
+
+  // Test that clients can send and receive Binders.
+  INamedCallback GetOtherTestService(String name);
+  boolean VerifyName(INamedCallback service, String name);
+
+  // Test that List<T> types work correctly.
+  List<String> ReverseStringList(in List<String> input,
+                                 out List<String> repeated);
+  List<IBinder> ReverseNamedCallbackList(in List<IBinder> input,
+                                         out List<IBinder> repeated);
+
+  FileDescriptor RepeatFileDescriptor(in FileDescriptor read);
+  FileDescriptor[] ReverseFileDescriptorArray(in FileDescriptor[] input,
+                                              out FileDescriptor[] repeated);
+
+  // Test that service specific exceptions work correctly.
+  void ThrowServiceException(int code);
+
+  // Test nullability
+  @nullable int[] RepeatNullableIntArray(in @nullable int[] input);
+  @nullable String RepeatNullableString(in @nullable String input);
+  @nullable List<String> RepeatNullableStringList(in @nullable List<String> input);
+  @nullable SimpleParcelable RepeatNullableParcelable(in @nullable SimpleParcelable input);
+
+  void TakesAnIBinder(in IBinder input);
+  void TakesAnIBinderList(in List<IBinder> input);
+  void TakesANullableIBinder(in @nullable IBinder input);
+  void TakesANullableIBinderList(in @nullable List<IBinder> input);
+
+  // Test utf8 decoding from utf16 wire format
+  @utf8InCpp String RepeatUtf8CppString(@utf8InCpp String token);
+  @nullable @utf8InCpp String RepeatNullableUtf8CppString(
+      @nullable @utf8InCpp String token);
+
+  @utf8InCpp String[]  ReverseUtf8CppString (in @utf8InCpp String[] input,
+                                             out @utf8InCpp String[] repeated);
+
+  @nullable @utf8InCpp List<String> ReverseUtf8CppStringList(
+      in @nullable @utf8InCpp List<String> input,
+      out @nullable @utf8InCpp List<String> repeated);
+
+  @nullable INamedCallback GetCallback(boolean return_null);
+}
diff --git a/aidl/tests/android/aidl/tests/SimpleParcelable.aidl b/aidl/tests/android/aidl/tests/SimpleParcelable.aidl
new file mode 100644
index 0000000..8573999
--- /dev/null
+++ b/aidl/tests/android/aidl/tests/SimpleParcelable.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+parcelable SimpleParcelable cpp_header "tests/simple_parcelable.h";
diff --git a/aidl/tests/end_to_end_tests.cpp b/aidl/tests/end_to_end_tests.cpp
new file mode 100644
index 0000000..480bfd9
--- /dev/null
+++ b/aidl/tests/end_to_end_tests.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+#include "aidl.h"
+#include "options.h"
+#include "tests/fake_io_delegate.h"
+#include "tests/test_data.h"
+#include "tests/test_util.h"
+
+using android::aidl::test::CanonicalNameToPath;
+using android::aidl::test::FakeIoDelegate;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace android {
+namespace aidl {
+
+class EndToEndTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+  }
+
+  void AddStubAidls(const char** parcelables, const char** interfaces,
+                    const char* cpp_header=nullptr) {
+    for ( ; *parcelables; ++parcelables) {
+      io_delegate_.AddStubParcelable(
+          *parcelables, (cpp_header) ? cpp_header : "");
+    }
+    for ( ; *interfaces; ++interfaces) {
+      io_delegate_.AddStubInterface(*interfaces);
+    }
+  }
+
+  void CheckFileContents(const string& rel_path,
+                         const string& expected_content) {
+    string actual_content;
+    ASSERT_TRUE(io_delegate_.GetWrittenContents(rel_path, &actual_content))
+        << "Expected aidl to write to " << rel_path << " but it did not.";
+
+    if (actual_content == expected_content) {
+      return;  // success!
+    }
+
+    test::PrintDiff(expected_content, actual_content);
+    FAIL() << "Actual contents of " << rel_path
+           << " did not match expected content";
+  }
+
+  FakeIoDelegate io_delegate_;
+};
+
+TEST_F(EndToEndTest, IExampleInterface) {
+  using namespace ::android::aidl::test_data::example_interface;
+
+  JavaOptions options;
+  options.fail_on_parcelable_ = true;
+  options.import_paths_.push_back("");
+  options.input_file_name_ = CanonicalNameToPath(kCanonicalName, ".aidl");
+  options.output_file_name_ = kJavaOutputPath;
+  options.dep_file_name_ = "an/arbitrary/path/to/deps.P";
+
+  // Load up our fake file system with data.
+  io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinition);
+  io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable",
+                                     {"Subclass1", "Subclass2"});
+  AddStubAidls(kImportedParcelables, kImportedInterfaces);
+
+  // Check that we parse correctly.
+  EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0);
+  CheckFileContents(kJavaOutputPath, kExpectedJavaOutput);
+  CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput);
+}
+
+TEST_F(EndToEndTest, IPingResponderCpp) {
+  using namespace ::android::aidl::test_data::ping_responder;
+
+  const string input_path = CanonicalNameToPath(kCanonicalName, ".aidl");
+  const string output_file = kCppOutputPath;
+  const size_t argc = 6;
+  const char* cmdline[argc + 1] = {
+      "aidl-cpp", "-ddeps.P", "-I.", input_path.c_str(), kGenHeaderDir,
+      output_file.c_str(), nullptr
+  };
+  auto options = CppOptions::Parse(argc, cmdline);
+
+  // Set up input paths.
+  io_delegate_.SetFileContents(input_path, kInterfaceDefinition);
+  AddStubAidls(kImportedParcelables, kImportedInterfaces, kCppParcelableHeader);
+
+  // Check that we parse and generate code correctly.
+  EXPECT_EQ(android::aidl::compile_aidl_to_cpp(*options, io_delegate_), 0);
+  CheckFileContents(output_file, kExpectedCppOutput);
+  CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput);
+  CheckFileContents(kGenClientHeaderPath, kExpectedBpHeaderOutput);
+  CheckFileContents(kGenServerHeaderPath, kExpectedBnHeaderOutput);
+  CheckFileContents(options->DependencyFilePath(), kExpectedCppDepsOutput);
+}
+
+TEST_F(EndToEndTest, StringConstantsInCpp) {
+  using namespace ::android::aidl::test_data::string_constants;
+
+  const string input_path = CanonicalNameToPath(kCanonicalName, ".aidl");
+  const string output_file = kCppOutputPath;
+  const size_t argc = 4;
+  const char* cmdline[argc + 1] = {
+      "aidl-cpp", input_path.c_str(), kGenHeaderDir,
+      output_file.c_str(), nullptr
+  };
+  auto options = CppOptions::Parse(argc, cmdline);
+
+  // Set up input paths.
+  io_delegate_.SetFileContents(input_path, kInterfaceDefinition);
+
+  // Check that we parse and generate code correctly.
+  EXPECT_EQ(android::aidl::compile_aidl_to_cpp(*options, io_delegate_), 0);
+  CheckFileContents(output_file, kExpectedCppOutput);
+  CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput);
+}
+
+TEST_F(EndToEndTest, StringConstantsInJava) {
+  using namespace ::android::aidl::test_data::string_constants;
+
+  const string input_path = CanonicalNameToPath(kCanonicalName, ".aidl");
+  const string output_file = kJavaOutputPath;
+  const size_t argc = 4;
+  const char* cmdline[argc + 1] = {
+    "aidl",
+    "-b",
+    input_path.c_str(),
+    output_file.c_str(),
+    nullptr,
+};
+  auto options = JavaOptions::Parse(argc, cmdline);
+
+  // Load up our fake file system with data.
+  io_delegate_.SetFileContents(input_path, kInterfaceDefinition);
+
+  // Check that we parse correctly.
+  EXPECT_EQ(android::aidl::compile_aidl_to_java(*options, io_delegate_), 0);
+  CheckFileContents(kJavaOutputPath, kExpectedJavaOutput);
+}
+
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/tests/fake_io_delegate.cpp b/aidl/tests/fake_io_delegate.cpp
new file mode 100644
index 0000000..c5575f6
--- /dev/null
+++ b/aidl/tests/fake_io_delegate.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fake_io_delegate.h"
+
+#include <android-base/stringprintf.h>
+
+#include "logging.h"
+#include "os.h"
+#include "tests/test_util.h"
+
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace android {
+namespace aidl {
+namespace test {
+
+// Claims to always write successfully, but can't close the file.
+class BrokenCodeWriter : public CodeWriter {
+  bool Write(const char* /* format */, ...) override {  return true; }
+  bool Close() override { return false; }
+  virtual ~BrokenCodeWriter() = default;
+};  // class BrokenCodeWriter
+
+unique_ptr<string> FakeIoDelegate::GetFileContents(
+    const string& relative_filename,
+    const string& content_suffix) const {
+  string filename = CleanPath(relative_filename);
+  unique_ptr<string> contents;
+  auto it = file_contents_.find(filename);
+  if (it == file_contents_.end()) {
+    return contents;
+  }
+  contents.reset(new string);
+  *contents = it->second;
+  contents->append(content_suffix);
+
+  return contents;
+}
+
+unique_ptr<LineReader> FakeIoDelegate::GetLineReader(
+    const string& file_path) const {
+  unique_ptr<LineReader> ret;
+  const auto& it = file_contents_.find(CleanPath(file_path));
+  if (it != file_contents_.cend()) {
+    ret = LineReader::ReadFromMemory(it->second);
+  }
+  return ret;
+}
+
+bool FakeIoDelegate::FileIsReadable(const string& path) const {
+  return file_contents_.find(CleanPath(path)) != file_contents_.end();
+}
+
+bool FakeIoDelegate::CreatedNestedDirs(
+    const std::string& /* base_dir */,
+    const std::vector<std::string>& /* nested_subdirs */) const {
+  // We don't test directory creation explicitly.
+  return true;
+}
+
+std::unique_ptr<CodeWriter> FakeIoDelegate::GetCodeWriter(
+    const std::string& file_path) const {
+  if (broken_files_.count(file_path) > 0) {
+    return unique_ptr<CodeWriter>(new BrokenCodeWriter);
+  }
+  removed_files_.erase(file_path);
+  written_file_contents_[file_path] = "";
+  return GetStringWriter(&written_file_contents_[file_path]);
+}
+
+void FakeIoDelegate::RemovePath(const std::string& file_path) const {
+  removed_files_.insert(file_path);
+}
+
+void FakeIoDelegate::SetFileContents(const string& filename,
+                                     const string& contents) {
+  file_contents_[filename] = contents;
+}
+
+void FakeIoDelegate::AddStubParcelable(const string& canonical_name,
+                                       const string& cpp_header) {
+  string package, class_name, rel_path;
+  SplitPackageClass(canonical_name, &rel_path, &package, &class_name);
+  string contents;
+  if (cpp_header.empty()) {
+    contents = StringPrintf("package %s;\nparcelable %s;",
+                            package.c_str(), class_name.c_str());
+  } else {
+    contents = StringPrintf("package %s;\nparcelable %s cpp_header \"%s\";",
+                            package.c_str(), class_name.c_str(),
+                            cpp_header.c_str());
+  }
+  SetFileContents(rel_path, contents);
+}
+
+void FakeIoDelegate::AddStubInterface(const string& canonical_name) {
+  string package, class_name, rel_path;
+  SplitPackageClass(canonical_name, &rel_path, &package, &class_name);
+  string contents = StringPrintf("package %s;\ninterface %s { }",
+                                 package.c_str(), class_name.c_str());
+  SetFileContents(rel_path, contents);
+}
+
+void FakeIoDelegate::AddCompoundParcelable(const string& canonical_name,
+                                           const vector<string>& subclasses) {
+  string package, class_name, rel_path;
+  SplitPackageClass(canonical_name, &rel_path, &package, &class_name);
+  string contents = StringPrintf("package %s;\n", package.c_str());
+  for (const string& subclass : subclasses) {
+    StringAppendF(&contents, "parcelable %s.%s;\n",
+                  class_name.c_str(), subclass.c_str());
+  }
+  SetFileContents(rel_path, contents);
+}
+
+void FakeIoDelegate::AddBrokenFilePath(const std::string& path) {
+  broken_files_.insert(path);
+}
+
+bool FakeIoDelegate::GetWrittenContents(const string& path, string* content) {
+  const auto it = written_file_contents_.find(path);
+  if (it == written_file_contents_.end()) {
+    return false;
+  }
+  if (content) {
+    *content = it->second;
+  }
+  return true;
+}
+
+bool FakeIoDelegate::PathWasRemoved(const std::string& path) {
+  if (removed_files_.count(path) > 0) {
+    return true;
+  }
+  return false;
+}
+
+string FakeIoDelegate::CleanPath(const string& path) const {
+  string clean_path = path;
+  while (clean_path.length() >= 2 &&
+         clean_path[0] == '.' &&
+         clean_path[1] == OS_PATH_SEPARATOR) {
+    clean_path = clean_path.substr(2);
+  }
+  return clean_path;
+}
+
+}  // namespace test
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/tests/fake_io_delegate.h b/aidl/tests/fake_io_delegate.h
new file mode 100644
index 0000000..aae2091
--- /dev/null
+++ b/aidl/tests/fake_io_delegate.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_TESTS_FAKE_IO_DELEGATE_H_
+#define AIDL_TESTS_FAKE_IO_DELEGATE_H_
+
+#include <android-base/macros.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "io_delegate.h"
+
+namespace android {
+namespace aidl {
+namespace test {
+
+class FakeIoDelegate : public IoDelegate {
+ public:
+  FakeIoDelegate() = default;
+  virtual ~FakeIoDelegate() = default;
+
+  // Overrides from the real IoDelegate
+  std::unique_ptr<std::string> GetFileContents(
+      const std::string& filename,
+      const std::string& append_content_suffix = "") const override;
+  std::unique_ptr<LineReader> GetLineReader(
+      const std::string& file_path) const override;
+  bool FileIsReadable(const std::string& path) const override;
+  bool CreatedNestedDirs(
+      const std::string& base_dir,
+      const std::vector<std::string>& nested_subdirs) const override;
+  std::unique_ptr<CodeWriter> GetCodeWriter(
+      const std::string& file_path) const override;
+  void RemovePath(const std::string& file_path) const override;
+
+  // Methods added to facilitate testing.
+  void SetFileContents(const std::string& filename,
+                       const std::string& contents);
+  void AddStubParcelable(const std::string& canonical_name,
+                         const std::string& cpp_header);
+  void AddStubInterface(const std::string& canonical_name);
+  void AddCompoundParcelable(const std::string& canonical_name,
+                             const std::vector<std::string>& subclasses);
+  void AddBrokenFilePath(const std::string& path);
+  // Returns true iff we've previously written to |path|.
+  // When we return true, we'll set *contents to the written string.
+  bool GetWrittenContents(const std::string& path, std::string* content);
+
+  bool PathWasRemoved(const std::string& path);
+
+ private:
+  // Remove leading "./" from |path|.
+  std::string CleanPath(const std::string& path) const;
+
+  std::map<std::string, std::string> file_contents_;
+  // Normally, writing to files leaves the IoDelegate unchanged, so
+  // GetCodeWriter is a const method.  However, for tests, we break this
+  // intentionally by storing the written strings.
+  mutable std::map<std::string, std::string> written_file_contents_;
+
+  // We normally just write to strings in |written_file_contents_| but for
+  // files in this list, we simulate I/O errors.
+  std::set<std::string> broken_files_;
+  mutable std::set<std::string> removed_files_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeIoDelegate);
+};  // class FakeIoDelegate
+
+}  // namespace test
+}  // namespace android
+}  // namespace aidl
+
+#endif // AIDL_TESTS_FAKE_IO_DELEGATE_H_
diff --git a/aidl/tests/integration-test.py b/aidl/tests/integration-test.py
new file mode 100755
index 0000000..0079ba9
--- /dev/null
+++ b/aidl/tests/integration-test.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+
+"""
+Test that aidl generates functional code by running it on an Android device.
+"""
+
+import argparse
+import pipes
+import subprocess
+import shlex
+
+JAVA_OUTPUT_READER = 'aidl_test_sentinel_searcher'
+NATIVE_TEST_CLIENT = 'aidl_test_client'
+NATIVE_TEST_SERVICE = 'aidl_test_service'
+
+TEST_FILTER_ALL = 'all'
+TEST_FILTER_JAVA = 'java'
+TEST_FILTER_NATIVE = 'native'
+
+JAVA_CLIENT_TIMEOUT_SECONDS = 30
+JAVA_LOG_FILE = '/data/data/android.aidl.tests/files/test-client.log'
+JAVA_SUCCESS_SENTINEL = '>>> Java Client Success <<<'
+JAVA_FAILURE_SENTINEL = '>>> Java Client Failure <<<'
+
+class TestFail(Exception):
+    """Raised on test failures."""
+    pass
+
+
+class ShellResult(object):
+    """Represents the result of running a shell command."""
+
+    def __init__(self, exit_status, stdout, stderr):
+        """Construct an instance.
+
+        Args:
+            exit_status: integer exit code of shell command
+            stdout: string stdout of shell command
+            stderr: string stderr of shell command
+        """
+        self.stdout = stdout
+        self.stderr = stderr
+        self.exit_status = exit_status
+
+    def printable_string(self):
+        """Get a string we could print to the logs and understand."""
+        output = []
+        output.append('stdout:')
+        for line in self.stdout.splitlines():
+            output.append('  > %s' % line)
+        output.append('stderr:')
+        for line in self.stderr.splitlines():
+            output.append('  > %s' % line)
+        return '\n'.join(output)
+
+
+class AdbHost(object):
+    """Represents a device connected via ADB."""
+
+    def __init__(self, device_serial=None, verbose=None):
+        """Construct an instance.
+
+        Args:
+            device_serial: options string serial number of attached device.
+            verbose: True iff we should print out ADB commands we run.
+        """
+        self._device_serial = device_serial
+        self._verbose = verbose
+
+    def run(self, command, background=False, ignore_status=False):
+        """Run a command on the device via adb shell.
+
+        Args:
+            command: string containing a shell command to run.
+            background: True iff we should run this command in the background.
+            ignore_status: True iff we should ignore the command's exit code.
+
+        Returns:
+            instance of ShellResult.
+
+        Raises:
+            subprocess.CalledProcessError on command exit != 0.
+        """
+        if background:
+            command = '( %s ) </dev/null >/dev/null 2>&1 &' % command
+        return self.adb('shell %s' % pipes.quote(command),
+                        ignore_status=ignore_status)
+
+    def mktemp(self):
+        """Make a temp file on the device.
+
+        Returns:
+            path to created file as a string
+
+        Raises:
+            subprocess.CalledProcessError on failure.
+        """
+        # Work around b/19635681
+        result = self.run('source /system/etc/mkshrc && mktemp')
+        return result.stdout.strip()
+
+    def adb(self, command, ignore_status=False):
+        """Run an ADB command (e.g. `adb sync`).
+
+        Args:
+            command: string containing command to run
+            ignore_status: True iff we should ignore the command's exit code.
+
+        Returns:
+            instance of ShellResult.
+
+        Raises:
+            subprocess.CalledProcessError on command exit != 0.
+        """
+        command = 'adb %s' % command
+        if self._verbose:
+            print(command)
+        p = subprocess.Popen(command, shell=True, close_fds=True,
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                             universal_newlines=True)
+        stdout, stderr = p.communicate()
+        if not ignore_status and p.returncode:
+            raise subprocess.CalledProcessError(p.returncode, command)
+        return ShellResult(p.returncode, stdout, stderr)
+
+
+def run_test(host, test_native, test_java):
+    """Body of the test.
+
+    Args:
+        host: AdbHost object to run tests on
+        test_native: True iff we should test native Binder clients.
+        test_java: True iff we shoudl test Java Binder clients.
+    """
+
+    print('Starting aidl integration testing...')
+
+    # Kill any previous test context
+    host.run('rm -f %s' % JAVA_LOG_FILE, ignore_status=True)
+    host.run('pkill %s' % NATIVE_TEST_SERVICE, ignore_status=True)
+
+    # Start up a native server
+    host.run(NATIVE_TEST_SERVICE, background=True)
+
+    # Start up clients
+    if test_native:
+        host.run('pkill %s' % NATIVE_TEST_CLIENT, ignore_status=True)
+        result = host.run(NATIVE_TEST_CLIENT, ignore_status=True)
+        if result.exit_status:
+            print(result.printable_string())
+            raise TestFail('%s returned status code %d' %
+                           (NATIVE_TEST_CLIENT, result.exit_status))
+
+    if test_java:
+        host.run('am start -S -a android.intent.action.MAIN '
+                 '-n android.aidl.tests/.TestServiceClient '
+                 '--es sentinel.success "%s" '
+                 '--es sentinel.failure "%s"' %
+                 (JAVA_SUCCESS_SENTINEL, JAVA_FAILURE_SENTINEL))
+        result = host.run('%s %d %s "%s" "%s"' %
+                          (JAVA_OUTPUT_READER, JAVA_CLIENT_TIMEOUT_SECONDS,
+                           JAVA_LOG_FILE, JAVA_SUCCESS_SENTINEL,
+                           JAVA_FAILURE_SENTINEL),
+                          ignore_status=True)
+        if result.exit_status:
+            print(result.printable_string())
+            raise TestFail('Java client did not complete successfully.')
+
+    print('Success!')
+
+
+def main():
+    """Main entry point."""
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument(
+            '--test-filter', default=TEST_FILTER_ALL,
+            choices=[TEST_FILTER_ALL, TEST_FILTER_JAVA, TEST_FILTER_NATIVE])
+    parser.add_argument('--verbose', '-v', action='store_true', default=False)
+    args = parser.parse_args()
+    host = AdbHost(verbose=args.verbose)
+    try:
+        # Tragically, SELinux interferes with our testing
+        host.run('setenforce 0')
+        run_test(host,
+                 args.test_filter in (TEST_FILTER_ALL, TEST_FILTER_NATIVE),
+                 args.test_filter in (TEST_FILTER_ALL, TEST_FILTER_JAVA))
+    finally:
+        host.run('setenforce 1')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/aidl/tests/java_app/AndroidManifest.xml b/aidl/tests/java_app/AndroidManifest.xml
new file mode 100644
index 0000000..9093892
--- /dev/null
+++ b/aidl/tests/java_app/AndroidManifest.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.aidl.tests">
+
+  <application android:label="@string/application_title">
+
+    <activity android:name="android.aidl.tests.TestServiceClient">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+  </application>
+</manifest>
diff --git a/aidl/tests/java_app/README b/aidl/tests/java_app/README
new file mode 100644
index 0000000..a3dfceb
--- /dev/null
+++ b/aidl/tests/java_app/README
@@ -0,0 +1,17 @@
+To use this APK do something like:
+
+1) Build your favorite AOSP flavor.
+2) Start an emulator:
+    $ emulator
+3) Push over hellod binary:
+    $ adb remount && adb sync
+4) Install the Java client:
+    $ adb install -r <path-to-APK-in-out-directory>
+5) Put selinux in permissive mode.
+6) Start hellod:
+    $ adb shell "(hellod ) </dev/null >/dev/null 2>&1 &"
+7) Start Java client:
+    $ adb shell am start -S -a android.intent.action.MAIN \
+                           -n "android.aidl.tests/.TestServiceClient"
+8) Watch output on logcat:
+    $ adb logcat -s TestServiceClient hellod
diff --git a/aidl/tests/java_app/resources/values/strings.xml b/aidl/tests/java_app/resources/values/strings.xml
new file mode 100644
index 0000000..d5ee63e
--- /dev/null
+++ b/aidl/tests/java_app/resources/values/strings.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Strictly speaking, we don't need this. However, without something in
+     resources/ the build rebuilds the APK despite having no changes to the
+     source code.  This seems to be because it fails to generate some
+     resources metafile (R.stamp?) -->
+<resources>
+  <string
+    name="application_title"
+    >AIDL Test Services</string>
+</resources>
diff --git a/aidl/tests/java_app/src/android/aidl/tests/NullableTests.java b/aidl/tests/java_app/src/android/aidl/tests/NullableTests.java
new file mode 100644
index 0000000..83a9877
--- /dev/null
+++ b/aidl/tests/java_app/src/android/aidl/tests/NullableTests.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+import android.aidl.tests.TestFailException;
+import android.os.IBinder;
+import java.util.ArrayList;
+import java.util.List;
+
+class NullableTests {
+    private static final String TAG = "TestServiceClient";
+    private ITestService mService;
+    private TestLogger mLog;
+
+    public NullableTests(ITestService service, TestLogger logger) {
+        mService = service;
+        mLog = logger;
+    }
+
+    public void checkNullHandling() throws TestFailException {
+        mLog.log("Checking that sending null strings reports an error...");
+        try {
+            String response = mService.RepeatString(null);
+            mLog.logAndThrow("Expected to fail on null string input!");
+        } catch (NullPointerException ex) {
+            mLog.log("Caught an exception on null string parameter (expected)");
+            mLog.log("null strings behave as expected");
+            return;
+        } catch (Exception ex) {
+            mLog.logAndThrow("Expected to receive NullPointerException on " +
+                             "null parameter, but got " + ex.toString());
+        }
+        mLog.logAndThrow("Expected to receive NullPointerException on " +
+                         "null parameter, but nothing was thrown??");
+    }
+
+    public void checkNullBinderDetection() throws TestFailException {
+        mLog.log("Checking that service handles @nullable IBinder...");
+        try {
+            mService.TakesAnIBinder(null);
+            mLog.logAndThrow("Expected to fail on null Binder!");
+        } catch (NullPointerException ex) {
+            mLog.log("Caught an exception on null Binder parameter (expected)");
+            return;
+        } catch (Exception ex) {
+            mLog.logAndThrow("Expected to receive NullPointerException," +
+                             "but got " + ex.toString());
+        }
+        mLog.logAndThrow("Expected to receive NullPointerException on " +
+                         "null parameter, but nothing was thrown??");
+    }
+
+    public void checkNullBinderInListDetection() throws TestFailException {
+        List<IBinder> listWithNulls = new ArrayList<IBinder>();
+        listWithNulls.add(null);
+        try {
+            mService.TakesAnIBinderList(listWithNulls);
+            mLog.logAndThrow("Expected to fail on list with null Binder!");
+        } catch (NullPointerException ex) {
+            mLog.log("Caught an exception on list with null Binder (expected)");
+            return;
+        } catch (Exception ex) {
+            mLog.logAndThrow("Expected to receive NullPointerException," +
+                             "but got " + ex.toString());
+        }
+        mLog.logAndThrow("Expected to receive NullPointerException on " +
+                         "null parameter, but nothing was thrown??");
+    }
+
+    public void checkNullInterfaceHandling() throws TestFailException {
+        mLog.log("Checking @nullable IInterface handling...");
+        try {
+            INamedCallback callback  = mService.GetCallback(false);
+            if (callback == null) {
+                mLog.logAndThrow("Expected to get non-null INamedCallback.");
+            }
+            callback  = mService.GetCallback(true);
+            if (callback != null) {
+                mLog.logAndThrow("Expected to get null INamedCallback.");
+            }
+        } catch (Exception ex) {
+            mLog.logAndThrow("Unexpected exception during @nullable IInterface test: " +
+                             ex.toString());
+        }
+        mLog.log("@nullable IInterface handling works as expected.");
+    }
+
+    public void runTests() throws TestFailException {
+        checkNullHandling();
+        checkNullBinderDetection();
+        checkNullBinderInListDetection();
+        checkNullInterfaceHandling();
+    }
+}
diff --git a/aidl/tests/java_app/src/android/aidl/tests/SimpleParcelable.java b/aidl/tests/java_app/src/android/aidl/tests/SimpleParcelable.java
new file mode 100644
index 0000000..1def98c
--- /dev/null
+++ b/aidl/tests/java_app/src/android/aidl/tests/SimpleParcelable.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class SimpleParcelable implements Parcelable {
+    private String mName;
+    private int mNumber;
+
+    SimpleParcelable() {}
+    SimpleParcelable(String name, int number) {
+        mName = name;
+        mNumber = number;
+    }
+
+    public int describeContents() { return 0; }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mName);
+        dest.writeInt(mNumber);
+    }
+
+    public void readFromParcel(Parcel source) {
+        mName = source.readString();
+        mNumber = source.readInt();
+    }
+
+    public boolean equals(Object o) {
+        if (o == null) {
+            return false;
+        }
+        if (!(o instanceof SimpleParcelable)) {
+            return false;
+        }
+        SimpleParcelable p = (SimpleParcelable)o;
+        if ((mName == null && p.mName != null) ||
+            (mName != null && !mName.equals(p.mName))) {
+            return false;
+        }
+        return mNumber == p.mNumber;
+    }
+
+    public String toString() {
+        return "SimpleParcelable(" + mName + ", " + mNumber + ")";
+    }
+
+    public static final Parcelable.Creator<SimpleParcelable> CREATOR =
+            new Parcelable.Creator<SimpleParcelable>() {
+        public SimpleParcelable createFromParcel(Parcel source) {
+            String name = source.readString();
+            int number = source.readInt();
+            return new SimpleParcelable(name, number);
+        }
+
+        public SimpleParcelable[] newArray(int size) {
+            return new SimpleParcelable[size];
+        }
+    };
+}
diff --git a/aidl/tests/java_app/src/android/aidl/tests/TestFailException.java b/aidl/tests/java_app/src/android/aidl/tests/TestFailException.java
new file mode 100644
index 0000000..de000fa
--- /dev/null
+++ b/aidl/tests/java_app/src/android/aidl/tests/TestFailException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+public class TestFailException extends Exception {
+    public TestFailException(String message) {
+        super(message);
+    }
+}
+
diff --git a/aidl/tests/java_app/src/android/aidl/tests/TestLogger.java b/aidl/tests/java_app/src/android/aidl/tests/TestLogger.java
new file mode 100644
index 0000000..b2e400b
--- /dev/null
+++ b/aidl/tests/java_app/src/android/aidl/tests/TestLogger.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+import android.util.Log;
+import java.io.PrintWriter;
+import java.io.IOException;
+import android.content.Context;
+
+public class TestLogger {
+    private static final String TAG = "TestServiceClient";
+    private PrintWriter mLogFile;
+
+    public TestLogger(Context context) {
+        try {
+            mLogFile = new PrintWriter(context.openFileOutput(
+                    "test-client.log", Context.MODE_PRIVATE));
+        } catch (IOException ex) {
+            throw new RuntimeException("Failed to open log file for writing.");
+        }
+    }
+
+    public void log(String line) {
+        Log.i(TAG, line);
+        mLogFile.println(line);
+    }
+
+    public void logAndThrow(String line) throws TestFailException {
+        Log.e(TAG, line);
+        mLogFile.println(line);
+        throw new TestFailException(line);
+    }
+
+    public void close() {
+        if (mLogFile != null) {
+            mLogFile.close();
+        }
+    }
+}
diff --git a/aidl/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/aidl/tests/java_app/src/android/aidl/tests/TestServiceClient.java
new file mode 100644
index 0000000..4af4aa0
--- /dev/null
+++ b/aidl/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+import android.aidl.tests.SimpleParcelable;
+import android.aidl.tests.TestFailException;
+import android.aidl.tests.TestLogger;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ServiceSpecificException;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+// Generated
+import android.aidl.tests.INamedCallback;
+import android.aidl.tests.ITestService;
+
+public class TestServiceClient extends Activity {
+    private static final String TAG = "TestServiceClient";
+
+    private TestLogger mLog;
+    private String mSuccessSentinel;
+    private String mFailureSentinel;
+
+    private void init() {
+        Intent intent = getIntent();
+        mLog = new TestLogger(this);
+        mLog.log("Reading sentinels from intent...");
+        mSuccessSentinel = intent.getStringExtra("sentinel.success");
+        mFailureSentinel = intent.getStringExtra("sentinel.failure");
+        if (mSuccessSentinel == null || mFailureSentinel == null) {
+            String message = "Failed to read intent extra input.";
+            Log.e(TAG, message);
+            mLog.close();
+            throw new RuntimeException(message);
+        }
+    }
+
+    private ITestService getService() throws TestFailException {
+        IBinder service = new ServiceManager().getService(
+                ITestService.class.getName());
+        if (service == null) {
+            mLog.logAndThrow("Failed to obtain binder...");
+        }
+        ITestService ret = ITestService.Stub.asInterface(service);
+        if (ret == null) {
+            mLog.logAndThrow("Failed to cast IBinder instance.");
+        }
+        return ret;
+    }
+
+    private void checkPrimitiveRepeat(ITestService service)
+            throws TestFailException {
+        mLog.log("Checking that service can repeat primitives back...");
+        try {
+            {
+                boolean query = true;
+                boolean response = service.RepeatBoolean(query);
+                if (query != response) {
+                    mLog.logAndThrow("Repeat with " + query +
+                                     " responded " + response);
+                }
+            }
+            {
+                char query = 'A';
+                char response = service.RepeatChar(query);
+                if (query != response) {
+                    mLog.logAndThrow("Repeat with " + query +
+                                     " responded " + response);
+                }
+            }
+            {
+                byte query = -128;
+                byte response = service.RepeatByte(query);
+                if (query != response) {
+                    mLog.logAndThrow("Repeat with " + query +
+                                     " responded " + response);
+                }
+            }
+            {
+                int query = 1 << 30;
+                int response = service.RepeatInt(query);
+                if (query != response) {
+                    mLog.logAndThrow("Repeat with " + query +
+                                     " responded " + response);
+                }
+            }
+            {
+                int query[] = {ITestService.TEST_CONSTANT,
+                               ITestService.TEST_CONSTANT2,
+                               ITestService.TEST_CONSTANT3,
+                               ITestService.TEST_CONSTANT4,
+                               ITestService.TEST_CONSTANT5,
+                               ITestService.TEST_CONSTANT6,
+                               ITestService.TEST_CONSTANT7,
+                               ITestService.TEST_CONSTANT8};
+                for (int i = 0; i < query.length; i++) {
+                    int response = service.RepeatInt(query[i]);
+                    if (query[i] != response) {
+                        mLog.logAndThrow("Repeat with " + query[i] +
+                                " responded " + response);
+                    }
+                }
+            }
+            {
+                long query = 1L << 60;
+                long response = service.RepeatLong(query);
+                if (query != response) {
+                    mLog.logAndThrow("Repeat with " + query +
+                                     " responded " + response);
+                }
+            }
+            {
+                float query = 1.0f/3.0f;
+                float response = service.RepeatFloat(query);
+                if (query != response) {
+                    mLog.logAndThrow("Repeat with " + query +
+                                     " responded " + response);
+                }
+            }
+            {
+                double query = 1.0/3.0;
+                double response = service.RepeatDouble(query);
+                if (query != response) {
+                    mLog.logAndThrow("Repeat with " + query +
+                                     " responded " + response);
+                }
+            }
+
+            List<String> queries = Arrays.asList(
+                "not empty", "", "\0",
+                ITestService.STRING_TEST_CONSTANT,
+                ITestService.STRING_TEST_CONSTANT2);
+            for (String query : queries) {
+                String response = service.RepeatString(query);
+                if (!query.equals(response)) {
+                    mLog.logAndThrow("Repeat request with '" + query + "'" +
+                                     " of length " + query.length() +
+                                     " responded with '" + response + "'" +
+                                     " of length " + response.length());
+                }
+            }
+        } catch (RemoteException ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Service failed to repeat a primitive back.");
+        }
+        mLog.log("...Basic primitive repeating works.");
+    }
+
+    private void checkArrayReversal(ITestService service)
+            throws TestFailException {
+        mLog.log("Checking that service can reverse and return arrays...");
+        try {
+            {
+                boolean[] input = {true, false, false, false};
+                boolean echoed[] = new boolean[input.length];
+                boolean[] reversed = service.ReverseBoolean(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (input[i] != reversed[j]) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+            {
+                byte[] input = {0, 1, 2};
+                byte echoed[] = new byte[input.length];
+                byte[] reversed = service.ReverseByte(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (input[i] != reversed[j]) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+            {
+                char[] input = {'A', 'B', 'C', 'D', 'E'};
+                char echoed[] = new char[input.length];
+                char[] reversed = service.ReverseChar(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (input[i] != reversed[j]) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+            {
+                int[] input = {-1, 0, 1, 2, 3, 4, 5, 6};
+                int echoed[] = new int[input.length];
+                int[] reversed = service.ReverseInt(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (input[i] != reversed[j]) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+            {
+                long[] input = {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8};
+                long echoed[] = new long[input.length];
+                long[] reversed = service.ReverseLong(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (input[i] != reversed[j]) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+            {
+                float[] input = {0.0f, 1.0f, -0.3f};
+                float echoed[] = new float[input.length];
+                float[] reversed = service.ReverseFloat(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (input[i] != reversed[j]) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+            {
+                double[] input = {-1.0, -4.0, -2.0};
+                double echoed[] = new double[input.length];
+                double[] reversed = service.ReverseDouble(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (input[i] != reversed[j]) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+            {
+                String[] input = {"For", "relaxing", "times"};
+                String echoed[] = new String[input.length];
+                String[] reversed = service.ReverseString(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (!input[i].equals(reversed[j])) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+        } catch (RemoteException ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Service failed to reverse an array.");
+        }
+        mLog.log("...service can reverse and return arrays.");
+    }
+
+    private void checkBinderExchange(
+                ITestService service) throws TestFailException {
+      mLog.log("Checking exchange of binders...");
+      try {
+          INamedCallback got = service.GetOtherTestService("Smythe");
+          mLog.log("Received test service");
+          String name = got.GetName();
+
+          if (!name.equals("Smythe")) {
+              mLog.logAndThrow("Tried to get service with name 'Smythe'" +
+                               " and found service with name '" + name + "'");
+          }
+
+          if (!service.VerifyName(got, "Smythe")) {
+              mLog.logAndThrow("Test service could not verify name of 'Smythe'");
+          }
+      } catch (RemoteException ex) {
+          mLog.log(ex.toString());
+          mLog.logAndThrow("Service failed to exchange binders.");
+      }
+      mLog.log("...Exchange of binders works");
+    }
+
+    private void checkListReversal(ITestService service)
+            throws TestFailException {
+        mLog.log("Checking that service can reverse and return lists...");
+        try {
+            {
+                List<String> input = Arrays.asList("Walk", "into", "Córdoba");
+                List<String> echoed = new ArrayList<String>();
+                List<String> reversed = service.ReverseStringList(input, echoed);
+                if (!input.equals(echoed)) {
+                    mLog.logAndThrow("Failed to echo input List<String> back.");
+                }
+                Collections.reverse(input);
+                if (!input.equals(reversed)) {
+                    mLog.logAndThrow("Reversed list is not correct.");
+                }
+            }
+        } catch (RemoteException ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Service failed to reverse an List<String>.");
+        }
+        mLog.log("...service can reverse and return lists.");
+    }
+
+    private void checkSimpleParcelables(ITestService service)
+            throws TestFailException {
+        mLog.log("Checking that service can repeat and reverse SimpleParcelable objects...");
+        try {
+            {
+                SimpleParcelable input = new SimpleParcelable("foo", 42);
+                SimpleParcelable out_param = new SimpleParcelable();
+                SimpleParcelable returned =
+                        service.RepeatSimpleParcelable(input, out_param);
+                if (!input.equals(out_param)) {
+                    mLog.log(input.toString() + " != " + out_param.toString());
+                    mLog.logAndThrow("out param SimpleParcelable was not equivalent");
+                }
+                if (!input.equals(returned)) {
+                    mLog.log(input.toString() + " != " + returned.toString());
+                    mLog.logAndThrow("returned SimpleParcelable was not equivalent");
+                }
+            }
+            {
+                SimpleParcelable[] input = new SimpleParcelable[3];
+                input[0] = new SimpleParcelable("a", 1);
+                input[1] = new SimpleParcelable("b", 2);
+                input[2] = new SimpleParcelable("c", 3);
+                SimpleParcelable[] repeated = new SimpleParcelable[3];
+                SimpleParcelable[] reversed = service.ReverseSimpleParcelables(
+                        input, repeated);
+                if (!Arrays.equals(input, repeated)) {
+                    mLog.logAndThrow(
+                            "Repeated list of SimpleParcelable objects did not match.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow(
+                            "Reversed list of SimpleParcelable objects had wrong length.");
+                }
+                for (int i = 0, k = input.length - 1;
+                     i < input.length;
+                     ++i, --k) {
+                    if (!input[i].equals(reversed[k])) {
+                        mLog.log(input[i].toString() + " != " +
+                                 reversed[k].toString());
+                        mLog.logAndThrow("reversed SimpleParcelable was not equivalent");
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Service failed to handle SimpleParcelable objects.");
+        }
+        mLog.log("...service can manipulate SimpleParcelable objects.");
+    }
+
+    private void checkPersistableBundles(ITestService service)
+            throws TestFailException {
+        mLog.log("Checking that service can repeat and reverse PersistableBundle objects...");
+        try {
+            {
+                PersistableBundle emptyBundle = new PersistableBundle();
+                PersistableBundle returned = service.RepeatPersistableBundle(emptyBundle);
+                if (emptyBundle.size() != 0 || returned.size() != 0) {
+                    mLog.log(emptyBundle.toString() + " != " + returned.toString());
+                    mLog.logAndThrow("returned empty PersistableBundle object was not equivalent");
+                }
+                mLog.log("...service can repeat and reverse empty PersistableBundle objects...");
+            }
+            {
+                final String testBoolKey = new String("testBool");
+                final String testIntKey = new String("testInt");
+                final String testNestedIntKey = new String("testNestedInt");
+                final String testLongKey = new String("testLong");
+                final String testDoubleKey = new String("testDouble");
+                final String testStringKey = new String("testString");
+                final String testBoolArrayKey = new String("testBoolArray");
+                final String testIntArrayKey = new String("testIntArray");
+                final String testLongArrayKey = new String("testLongArray");
+                final String testDoubleArrayKey = new String("testDoubleArray");
+                final String testStringArrayKey = new String("testStringArray");
+                final String testPersistableBundleKey = new String("testPersistableBundle");
+                PersistableBundle nonEmptyBundle = new PersistableBundle();
+                nonEmptyBundle.putBoolean(testBoolKey, false);
+                nonEmptyBundle.putInt(testIntKey, 33);
+                nonEmptyBundle.putLong(testLongKey, 34359738368L);
+                nonEmptyBundle.putDouble(testDoubleKey, 1.1);
+                nonEmptyBundle.putString(testStringKey, new String("Woot!"));
+                nonEmptyBundle.putBooleanArray(testBoolArrayKey, new boolean[] {true, false, true});
+                nonEmptyBundle.putIntArray(testIntArrayKey, new int[] {33, 44, 55, 142});
+                nonEmptyBundle.putLongArray(
+                    testLongArrayKey, new long[] {34L, 8371L, 34359738375L});
+                nonEmptyBundle.putDoubleArray(testDoubleArrayKey, new double[] {2.2, 5.4});
+                nonEmptyBundle.putStringArray(testStringArrayKey, new String[] {"hello", "world!"});
+                PersistableBundle testNestedPersistableBundle = new PersistableBundle();
+                testNestedPersistableBundle.putInt(testNestedIntKey, 345);
+                nonEmptyBundle.putPersistableBundle(
+                    testPersistableBundleKey, testNestedPersistableBundle);
+                PersistableBundle returned = service.RepeatPersistableBundle(nonEmptyBundle);
+                if (returned.size() != nonEmptyBundle.size()
+                    || returned.getBoolean(testBoolKey) != nonEmptyBundle.getBoolean(testBoolKey)
+                    || returned.getInt(testIntKey) != nonEmptyBundle.getInt(testIntKey)
+                    || returned.getLong(testLongKey) != nonEmptyBundle.getLong(testLongKey)
+                    || returned.getDouble(testDoubleKey) != nonEmptyBundle.getDouble(testDoubleKey)
+                    || !returned.getString(testStringKey)
+                                .equals(nonEmptyBundle.getString(testStringKey))
+                    || !Arrays.equals(nonEmptyBundle.getBooleanArray(testBoolArrayKey),
+                                      returned.getBooleanArray(testBoolArrayKey))
+                    || !Arrays.equals(nonEmptyBundle.getIntArray(testIntArrayKey),
+                                      returned.getIntArray(testIntArrayKey))
+                    || !Arrays.equals(nonEmptyBundle.getLongArray(testLongArrayKey),
+                                      returned.getLongArray(testLongArrayKey))
+                    || !Arrays.equals(nonEmptyBundle.getDoubleArray(testDoubleArrayKey),
+                                      returned.getDoubleArray(testDoubleArrayKey))
+                    || !Arrays.equals(nonEmptyBundle.getStringArray(testStringArrayKey),
+                                      returned.getStringArray(testStringArrayKey))) {
+                    PersistableBundle temp =
+                        returned.getPersistableBundle(testPersistableBundleKey);
+                    if (temp == null
+                        || temp.getInt(testNestedIntKey)
+                            != testNestedPersistableBundle.getInt(testNestedIntKey)) {
+                        mLog.log(nonEmptyBundle.toString() + " != " + returned.toString());
+                        mLog.logAndThrow("returned non-empty PersistableBundle " +
+                                         "object was not equivalent");
+                    }
+                }
+                mLog.log("...service can repeat and reverse non-empty " +
+                         "PersistableBundle objects...");
+            }
+            {
+                PersistableBundle[] input = new PersistableBundle[3];
+                PersistableBundle first = new PersistableBundle();
+                PersistableBundle second = new PersistableBundle();
+                PersistableBundle third = new PersistableBundle();
+                final String testIntKey = new String("testInt");
+                final String testLongKey = new String("testLong");
+                final String testDoubleKey = new String("testDouble");
+                first.putInt(testIntKey, 1231);
+                second.putLong(testLongKey, 222222L);
+                third.putDouble(testDoubleKey, 10.8);
+                input[0] = first;
+                input[1] = second;
+                input[2] = third;
+                final int original_input_size = input.length;
+                PersistableBundle[] repeated = new PersistableBundle[input.length];
+                PersistableBundle[] reversed = service.ReversePersistableBundles(input, repeated);
+                if (input.length != repeated.length || input.length != original_input_size) {
+                    mLog.logAndThrow("Repeated list of PersistableBundle objects had " +
+                                     "wrong length.");
+                }
+                if (input[0].getInt(testIntKey) != repeated[0].getInt(testIntKey)
+                    || input[1].getLong(testLongKey) != repeated[1].getLong(testLongKey)
+                    || input[2].getDouble(testDoubleKey) != repeated[2].getDouble(testDoubleKey)) {
+                    mLog.logAndThrow("Repeated list of PersistableBundle objects did not match.");
+                }
+                if (input.length != reversed.length || input.length != original_input_size) {
+                    mLog.logAndThrow("Reversed list of PersistableBundle objects had " +
+                                     "wrong length.");
+                }
+                if (input[0].getInt(testIntKey) != reversed[2].getInt(testIntKey)
+                    || input[1].getLong(testLongKey) != reversed[1].getLong(testLongKey)
+                    || input[2].getDouble(testDoubleKey) != reversed[0].getDouble(testDoubleKey)) {
+                    mLog.logAndThrow("reversed PersistableBundle objects were not equivalent");
+                }
+                mLog.log("...service can repeat and reverse arrays of " +
+                         "non-empty PersistableBundle objects...");
+            }
+        } catch (Exception ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Service failed to handle PersistableBundle objects.");
+        }
+        mLog.log("...service can manipulate PersistableBundle objects.");
+    }
+
+    private void checkFileDescriptorPassing(ITestService service)
+            throws TestFailException {
+        mLog.log("Checking that service can receive and return file descriptors...");
+        try {
+            FileOutputStream fileOutputStream =
+                    openFileOutput("test-dummy", Context.MODE_PRIVATE);
+
+            FileDescriptor descriptor = fileOutputStream.getFD();
+            FileDescriptor journeyed = service.RepeatFileDescriptor(descriptor);
+            fileOutputStream.close();
+
+            FileOutputStream journeyedStream = new FileOutputStream(journeyed);
+
+            String testData = "FrazzleSnazzleFlimFlamFlibbityGumboChops";
+            byte[] output = testData.getBytes();
+            journeyedStream.write(output);
+            journeyedStream.close();
+
+            FileInputStream fileInputStream = openFileInput("test-dummy");
+            byte[] input = new byte[output.length];
+            if (fileInputStream.read(input) != input.length) {
+                mLog.logAndThrow("Read short count from file");
+            }
+
+            if (!Arrays.equals(input, output)) {
+                mLog.logAndThrow("Read incorrect data");
+            }
+        } catch (RemoteException ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Service failed to repeat a file descriptor.");
+        } catch (IOException ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Exception while operating on temporary file");
+        }
+        mLog.log("...service can receive and return file descriptors.");
+    }
+
+    private void checkServiceSpecificExceptions(
+                ITestService service) throws TestFailException {
+        mLog.log("Checking application exceptions...");
+        for (int i = -1; i < 2; ++i) {
+            try {
+                service.ThrowServiceException(i);
+            } catch (RemoteException ex) {
+                mLog.logAndThrow("Service threw RemoteException: " +
+                                 ex.toString());
+            } catch (ServiceSpecificException ex) {
+                if (ex.errorCode != i) {
+                    mLog.logAndThrow("Service threw wrong error code: " + i);
+                }
+            }
+        }
+        mLog.log("...application exceptions work");
+    }
+
+    private void checkUtf8Strings(ITestService service)
+            throws TestFailException {
+        mLog.log("Checking that service can work with UTF8 strings...");
+        // Note that Java's underlying encoding is UTF16.
+        final List<String> utf8_queries = Arrays.asList(
+              "typical string",
+              "",
+              "\0\0\0",
+              // Java doesn't handle unicode code points above U+FFFF well.
+              new String(Character.toChars(0x1F701)) + "\u03A9");
+        try {
+            for (String query : utf8_queries) {
+                String response = service.RepeatUtf8CppString(query);
+                if (!query.equals(response)) {
+                    mLog.logAndThrow("Repeat request with '" + query + "'" +
+                                     " of length " + query.length() +
+                                     " responded with '" + response + "'" +
+                                     " of length " + response.length());
+                }
+            }
+            {
+                String[] input = (String[])utf8_queries.toArray();
+                String echoed[] = new String[input.length];
+                String[] reversed = service.ReverseUtf8CppString(input, echoed);
+                if (!Arrays.equals(input, echoed)) {
+                    mLog.logAndThrow("Failed to echo utf8 input array back.");
+                }
+                if (input.length != reversed.length) {
+                    mLog.logAndThrow("Reversed utf8 array is the wrong size.");
+                }
+                for (int i = 0; i < input.length; ++i) {
+                    int j = reversed.length - (1 + i);
+                    if (!input[i].equals(reversed[j])) {
+                        mLog.logAndThrow(
+                                "input[" + i + "] = " + input[i] +
+                                " but reversed value = " + reversed[j]);
+                    }
+                }
+            }
+        } catch (RemoteException ex) {
+            mLog.log(ex.toString());
+            mLog.logAndThrow("Service failed to handle utf8 strings.");
+        }
+        mLog.log("...UTF8 annotations work.");
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "Starting!");
+        try {
+          init();
+          ITestService service = getService();
+          checkPrimitiveRepeat(service);
+          checkArrayReversal(service);
+          checkBinderExchange(service);
+          checkListReversal(service);
+          checkSimpleParcelables(service);
+          checkPersistableBundles(service);
+          checkFileDescriptorPassing(service);
+          checkServiceSpecificExceptions(service);
+          checkUtf8Strings(service);
+          new NullableTests(service, mLog).runTests();
+
+          mLog.log(mSuccessSentinel);
+        } catch (TestFailException e) {
+            mLog.log(mFailureSentinel);
+            throw new RuntimeException(e);
+        } finally {
+            if (mLog != null) {
+                mLog.close();
+            }
+        }
+    }
+}
diff --git a/aidl/tests/main.cpp b/aidl/tests/main.cpp
new file mode 100644
index 0000000..4d820af
--- /dev/null
+++ b/aidl/tests/main.cpp
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/aidl/tests/simple_parcelable.cpp b/aidl/tests/simple_parcelable.cpp
new file mode 100644
index 0000000..e092d25
--- /dev/null
+++ b/aidl/tests/simple_parcelable.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tests/simple_parcelable.h"
+
+#include <android-base/stringprintf.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace aidl {
+namespace tests {
+
+SimpleParcelable::SimpleParcelable(const std::string& name, int32_t number)
+    : name_(name.c_str(), name.length()),
+      number_(number) {}
+
+status_t SimpleParcelable::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeString16(name_);
+  if (status != OK) {
+    return status;
+  }
+  status = parcel->writeInt32(number_);
+  return status;
+}
+
+status_t SimpleParcelable::readFromParcel(const Parcel* parcel) {
+  status_t status = parcel->readString16(&name_);
+  if (status != OK) {
+    return status;
+  }
+  return parcel->readInt32(&number_);
+}
+
+std::string SimpleParcelable::toString() const {
+    return StringPrintf("%s(%d)", String8(name_).string(), number_);
+}
+
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/simple_parcelable.h b/aidl/tests/simple_parcelable.h
new file mode 100644
index 0000000..52a20de
--- /dev/null
+++ b/aidl/tests/simple_parcelable.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_TESTS_SIMPLE_PARCELABLE_H_
+#define AIDL_TESTS_SIMPLE_PARCELABLE_H_
+
+#include <cstdint>
+#include <string>
+
+#include <binder/Parcelable.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+namespace android {
+namespace aidl {
+namespace tests {
+
+class SimpleParcelable : public Parcelable {
+ public:
+  SimpleParcelable() = default;
+  SimpleParcelable(const std::string& name, int32_t number);
+  virtual ~SimpleParcelable() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+
+  std::string toString() const;
+
+  friend bool operator==(const SimpleParcelable& lhs,
+                         const SimpleParcelable& rhs) {
+    return (lhs.name_ == rhs.name_) && (lhs.number_ == rhs.number_);
+  }
+  friend bool operator!=(const SimpleParcelable& lhs,
+                         const SimpleParcelable& rhs) {
+    return !(lhs == rhs);
+  }
+
+ private:
+  String16 name_;
+  int32_t number_ = 0;
+};  // class SimpleParcelable
+
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
+
+#endif  // AIDL_TESTS_SIMPLE_PARCELABLE_H_
diff --git a/aidl/tests/test_data.h b/aidl/tests/test_data.h
new file mode 100644
index 0000000..d3a5f6c
--- /dev/null
+++ b/aidl/tests/test_data.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_TESTS_TEST_DATA_H_
+#define AIDL_TESTS_TEST_DATA_H_
+
+namespace android {
+namespace aidl {
+namespace test_data {
+
+namespace example_interface {
+
+extern const char kCanonicalName[];
+extern const char kJavaOutputPath[];
+extern const char kInterfaceDefinition[];
+extern const char* kImportedParcelables[];
+extern const char* kImportedInterfaces[];
+
+extern const char kExpectedJavaDepsOutput[];
+extern const char kExpectedJavaOutput[];
+
+}  // namespace example_interface
+
+namespace ping_responder {
+
+extern const char kCanonicalName[];
+extern const char kInterfaceDefinition[];
+
+extern const char kCppOutputPath[];
+extern const char kCppParcelableHeader[];
+extern const char* kImportedParcelables[];
+extern const char* kImportedInterfaces[];
+
+extern const char kGenHeaderDir[];
+extern const char kGenInterfaceHeaderPath[];
+extern const char kGenClientHeaderPath[];
+extern const char kGenServerHeaderPath[];
+
+extern const char kExpectedCppDepsOutput[];
+
+extern const char kExpectedCppOutput[];
+extern const char kExpectedIHeaderOutput[];
+extern const char kExpectedBpHeaderOutput[];
+extern const char kExpectedBnHeaderOutput[];
+
+}  // namespace ping_responder
+
+namespace string_constants {
+
+extern const char kCanonicalName[];
+extern const char kInterfaceDefinition[];
+
+extern const char kJavaOutputPath[];
+extern const char kExpectedJavaOutput[];
+
+extern const char kCppOutputPath[];
+extern const char kGenHeaderDir[];
+extern const char kGenInterfaceHeaderPath[];
+extern const char kExpectedIHeaderOutput[];
+extern const char kExpectedCppOutput[];
+
+}  // namespace string_constants
+
+}  // namespace test_data
+}  // namespace aidl
+}  // namespace android
+
+#endif // AIDL_TESTS_TEST_DATA_H_
diff --git a/aidl/tests/test_data_example_interface.cpp b/aidl/tests/test_data_example_interface.cpp
new file mode 100644
index 0000000..81b919f
--- /dev/null
+++ b/aidl/tests/test_data_example_interface.cpp
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tests/test_data.h"
+
+namespace android {
+namespace aidl {
+namespace test_data {
+namespace example_interface {
+
+const char kCanonicalName[] = "android.test.IExampleInterface";
+
+const char kJavaOutputPath[] = "some/path/to/output.java";
+
+const char* kImportedParcelables[] = {
+  "android.foo.ExampleParcelable",
+  nullptr,
+};
+
+const char* kImportedInterfaces[] = {
+  "android.bar.IAuxInterface",
+  "android.test.IAuxInterface2",
+  nullptr,
+};
+
+const char kInterfaceDefinition[] = R"(
+package android.test;
+
+import android.foo.ExampleParcelable;
+import android.test.CompoundParcelable;
+import android.bar.IAuxInterface;
+import android.test.IAuxInterface2;
+
+interface IExampleInterface {
+    const int EXAMPLE_CONSTANT = 3;
+    boolean isEnabled();
+    int getState();
+    String getAddress();
+
+    /* Test long comment */
+    ExampleParcelable[] getParcelables();
+
+    // Test short comment
+    boolean setScanMode(int mode, int duration);
+
+    /* Test long comment */
+    // And short comment
+    void registerBinder(IAuxInterface foo);
+    IExampleInterface getRecursiveBinder();
+
+    int takesAnInterface(in IAuxInterface2 arg);
+    int takesAParcelable(in CompoundParcelable.Subclass1 arg,
+                         inout CompoundParcelable.Subclass2 arg2);
+}
+)";
+
+const char kExpectedJavaDepsOutput[] =
+R"(some/path/to/output.java : \
+  android/test/IExampleInterface.aidl \
+  ./android/foo/ExampleParcelable.aidl \
+  ./android/test/CompoundParcelable.aidl \
+  ./android/bar/IAuxInterface.aidl \
+  ./android/test/IAuxInterface2.aidl
+
+android/test/IExampleInterface.aidl :
+./android/foo/ExampleParcelable.aidl :
+./android/test/CompoundParcelable.aidl :
+./android/bar/IAuxInterface.aidl :
+./android/test/IAuxInterface2.aidl :
+)";
+
+const char kExpectedJavaOutput[] =
+R"(/*
+ * This file is auto-generated.  DO NOT MODIFY.
+ * Original file: android/test/IExampleInterface.aidl
+ */
+package android.test;
+public interface IExampleInterface extends android.os.IInterface
+{
+/** Local-side IPC implementation stub class. */
+public static abstract class Stub extends android.os.Binder implements android.test.IExampleInterface
+{
+private static final java.lang.String DESCRIPTOR = "android.test.IExampleInterface";
+/** Construct the stub at attach it to the interface. */
+public Stub()
+{
+this.attachInterface(this, DESCRIPTOR);
+}
+/**
+ * Cast an IBinder object into an android.test.IExampleInterface interface,
+ * generating a proxy if needed.
+ */
+public static android.test.IExampleInterface asInterface(android.os.IBinder obj)
+{
+if ((obj==null)) {
+return null;
+}
+android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+if (((iin!=null)&&(iin instanceof android.test.IExampleInterface))) {
+return ((android.test.IExampleInterface)iin);
+}
+return new android.test.IExampleInterface.Stub.Proxy(obj);
+}
+@Override public android.os.IBinder asBinder()
+{
+return this;
+}
+@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
+{
+switch (code)
+{
+case INTERFACE_TRANSACTION:
+{
+reply.writeString(DESCRIPTOR);
+return true;
+}
+case TRANSACTION_isEnabled:
+{
+data.enforceInterface(DESCRIPTOR);
+boolean _result = this.isEnabled();
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_getState:
+{
+data.enforceInterface(DESCRIPTOR);
+int _result = this.getState();
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_getAddress:
+{
+data.enforceInterface(DESCRIPTOR);
+java.lang.String _result = this.getAddress();
+reply.writeNoException();
+reply.writeString(_result);
+return true;
+}
+case TRANSACTION_getParcelables:
+{
+data.enforceInterface(DESCRIPTOR);
+android.foo.ExampleParcelable[] _result = this.getParcelables();
+reply.writeNoException();
+reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+return true;
+}
+case TRANSACTION_setScanMode:
+{
+data.enforceInterface(DESCRIPTOR);
+int _arg0;
+_arg0 = data.readInt();
+int _arg1;
+_arg1 = data.readInt();
+boolean _result = this.setScanMode(_arg0, _arg1);
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_registerBinder:
+{
+data.enforceInterface(DESCRIPTOR);
+android.bar.IAuxInterface _arg0;
+_arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder());
+this.registerBinder(_arg0);
+reply.writeNoException();
+return true;
+}
+case TRANSACTION_getRecursiveBinder:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IExampleInterface _result = this.getRecursiveBinder();
+reply.writeNoException();
+reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
+return true;
+}
+case TRANSACTION_takesAnInterface:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IAuxInterface2 _arg0;
+_arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder());
+int _result = this.takesAnInterface(_arg0);
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_takesAParcelable:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.CompoundParcelable.Subclass1 _arg0;
+if ((0!=data.readInt())) {
+_arg0 = android.test.CompoundParcelable.Subclass1.CREATOR.createFromParcel(data);
+}
+else {
+_arg0 = null;
+}
+android.test.CompoundParcelable.Subclass2 _arg1;
+if ((0!=data.readInt())) {
+_arg1 = android.test.CompoundParcelable.Subclass2.CREATOR.createFromParcel(data);
+}
+else {
+_arg1 = null;
+}
+int _result = this.takesAParcelable(_arg0, _arg1);
+reply.writeNoException();
+reply.writeInt(_result);
+if ((_arg1!=null)) {
+reply.writeInt(1);
+_arg1.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+}
+else {
+reply.writeInt(0);
+}
+return true;
+}
+}
+return super.onTransact(code, data, reply, flags);
+}
+private static class Proxy implements android.test.IExampleInterface
+{
+private android.os.IBinder mRemote;
+Proxy(android.os.IBinder remote)
+{
+mRemote = remote;
+}
+@Override public android.os.IBinder asBinder()
+{
+return mRemote;
+}
+public java.lang.String getInterfaceDescriptor()
+{
+return DESCRIPTOR;
+}
+@Override public boolean isEnabled() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int getState() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public java.lang.String getAddress() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+java.lang.String _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readString();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+/* Test long comment */
+@Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.foo.ExampleParcelable[] _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0);
+_reply.readException();
+_result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR);
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+// Test short comment
+
+@Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeInt(mode);
+_data.writeInt(duration);
+mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+/* Test long comment */// And short comment
+
+@Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0);
+_reply.readException();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+}
+@Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.test.IExampleInterface _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0);
+_reply.readException();
+_result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+if ((arg!=null)) {
+_data.writeInt(1);
+arg.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+if ((arg2!=null)) {
+_data.writeInt(1);
+arg2.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+if ((0!=_reply.readInt())) {
+arg2.readFromParcel(_reply);
+}
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+}
+static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
+static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
+static final int TRANSACTION_getAddress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
+static final int TRANSACTION_getParcelables = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
+static final int TRANSACTION_setScanMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
+static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
+static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
+static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
+static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
+}
+public static final int EXAMPLE_CONSTANT = 3;
+public boolean isEnabled() throws android.os.RemoteException;
+public int getState() throws android.os.RemoteException;
+public java.lang.String getAddress() throws android.os.RemoteException;
+/* Test long comment */
+public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
+// Test short comment
+
+public boolean setScanMode(int mode, int duration) throws android.os.RemoteException;
+/* Test long comment */// And short comment
+
+public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException;
+public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException;
+public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException;
+public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException;
+}
+)";
+
+}  // namespace example_interface
+}  // namespace test_data
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/test_data_ping_responder.cpp b/aidl/tests/test_data_ping_responder.cpp
new file mode 100644
index 0000000..40cb602
--- /dev/null
+++ b/aidl/tests/test_data_ping_responder.cpp
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tests/test_data.h"
+
+namespace android {
+namespace aidl {
+namespace test_data {
+namespace ping_responder {
+
+const char kCanonicalName[] = "android.os.IPingResponder";
+const char kInterfaceDefinition[] = R"(
+package android.os;
+
+import bar.Unused;
+
+interface IPingResponder {
+  String Ping(String input);
+
+  @nullable
+  String NullablePing(@nullable String input);
+
+  @utf8InCpp
+  String Utf8Ping(@utf8InCpp String input);
+
+  @utf8InCpp @nullable
+  String NullableUtf8Ping(@utf8InCpp @nullable String input);
+}
+)";
+
+const char kCppOutputPath[] = "some/path/to/output.cpp";
+
+const char kCppParcelableHeader[] = "cpp-header-str";
+
+const char* kImportedParcelables[] = {
+  "bar.Unused",
+  nullptr,
+};
+
+const char* kImportedInterfaces[] = {
+  nullptr,
+};
+
+const char kGenHeaderDir[] = "some/path";
+const char kGenInterfaceHeaderPath[] = "some/path/android/os/IPingResponder.h";
+const char kGenClientHeaderPath[] = "some/path/android/os/BpPingResponder.h";
+const char kGenServerHeaderPath[] = "some/path/android/os/BnPingResponder.h";
+
+const char kExpectedCppDepsOutput[] =
+R"(some/path/to/output.cpp : \
+  android/os/IPingResponder.aidl \
+  ./bar/Unused.aidl
+
+android/os/IPingResponder.aidl :
+./bar/Unused.aidl :
+
+some/path/android/os/BpPingResponder.h \
+    some/path/android/os/BnPingResponder.h \
+    some/path/android/os/IPingResponder.h : \
+    android/os/IPingResponder.aidl \
+    ./bar/Unused.aidl
+)";
+
+const char kExpectedCppOutput[] =
+R"(#include <android/os/IPingResponder.h>
+#include <android/os/BpPingResponder.h>
+
+namespace android {
+
+namespace os {
+
+IMPLEMENT_META_INTERFACE(PingResponder, "android.os.IPingResponder")
+
+}  // namespace os
+
+}  // namespace android
+#include <android/os/BpPingResponder.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+BpPingResponder::BpPingResponder(const ::android::sp<::android::IBinder>& _aidl_impl)
+    : BpInterface<IPingResponder>(_aidl_impl){
+}
+
+::android::binder::Status BpPingResponder::Ping(const ::android::String16& input, ::android::String16* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeString16(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IPingResponder::PING, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readString16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpPingResponder::NullablePing(const ::std::unique_ptr<::android::String16>& input, ::std::unique_ptr<::android::String16>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeString16(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IPingResponder::NULLABLEPING, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readString16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpPingResponder::Utf8Ping(const ::std::string& input, ::std::string* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IPingResponder::UTF8PING, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readUtf8FromUtf16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+::android::binder::Status BpPingResponder::NullableUtf8Ping(const ::std::unique_ptr<::std::string>& input, ::std::unique_ptr<::std::string>* _aidl_return) {
+::android::Parcel _aidl_data;
+::android::Parcel _aidl_reply;
+::android::status_t _aidl_ret_status = ::android::OK;
+::android::binder::Status _aidl_status;
+_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(input);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = remote()->transact(IPingResponder::NULLABLEUTF8PING, _aidl_data, &_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+if (!_aidl_status.isOk()) {
+return _aidl_status;
+}
+_aidl_ret_status = _aidl_reply.readUtf8FromUtf16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+goto _aidl_error;
+}
+_aidl_error:
+_aidl_status.setFromStatusT(_aidl_ret_status);
+return _aidl_status;
+}
+
+}  // namespace os
+
+}  // namespace android
+#include <android/os/BnPingResponder.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+::android::status_t BnPingResponder::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
+::android::status_t _aidl_ret_status = ::android::OK;
+switch (_aidl_code) {
+case Call::PING:
+{
+::android::String16 in_input;
+::android::String16 _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readString16(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(Ping(in_input, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeString16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::NULLABLEPING:
+{
+::std::unique_ptr<::android::String16> in_input;
+::std::unique_ptr<::android::String16> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readString16(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(NullablePing(in_input, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeString16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::UTF8PING:
+{
+::std::string in_input;
+::std::string _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(Utf8Ping(in_input, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeUtf8AsUtf16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+case Call::NULLABLEUTF8PING:
+{
+::std::unique_ptr<::std::string> in_input;
+::std::unique_ptr<::std::string> _aidl_return;
+if (!(_aidl_data.checkInterface(this))) {
+_aidl_ret_status = ::android::BAD_TYPE;
+break;
+}
+_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_input);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+::android::binder::Status _aidl_status(NullableUtf8Ping(in_input, &_aidl_return));
+_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+if (!_aidl_status.isOk()) {
+break;
+}
+_aidl_ret_status = _aidl_reply->writeUtf8AsUtf16(_aidl_return);
+if (((_aidl_ret_status) != (::android::OK))) {
+break;
+}
+}
+break;
+default:
+{
+_aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
+}
+break;
+}
+if (_aidl_ret_status == ::android::UNEXPECTED_NULL) {
+_aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply);
+}
+return _aidl_ret_status;
+}
+
+}  // namespace os
+
+}  // namespace android
+)";
+
+const char kExpectedIHeaderOutput[] =
+R"(#ifndef AIDL_GENERATED_ANDROID_OS_I_PING_RESPONDER_H_
+#define AIDL_GENERATED_ANDROID_OS_I_PING_RESPONDER_H_
+
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <binder/Status.h>
+#include <memory>
+#include <string>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace os {
+
+class IPingResponder : public ::android::IInterface {
+public:
+DECLARE_META_INTERFACE(PingResponder)
+virtual ::android::binder::Status Ping(const ::android::String16& input, ::android::String16* _aidl_return) = 0;
+virtual ::android::binder::Status NullablePing(const ::std::unique_ptr<::android::String16>& input, ::std::unique_ptr<::android::String16>* _aidl_return) = 0;
+virtual ::android::binder::Status Utf8Ping(const ::std::string& input, ::std::string* _aidl_return) = 0;
+virtual ::android::binder::Status NullableUtf8Ping(const ::std::unique_ptr<::std::string>& input, ::std::unique_ptr<::std::string>* _aidl_return) = 0;
+enum Call {
+  PING = ::android::IBinder::FIRST_CALL_TRANSACTION + 0,
+  NULLABLEPING = ::android::IBinder::FIRST_CALL_TRANSACTION + 1,
+  UTF8PING = ::android::IBinder::FIRST_CALL_TRANSACTION + 2,
+  NULLABLEUTF8PING = ::android::IBinder::FIRST_CALL_TRANSACTION + 3,
+};
+};  // class IPingResponder
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // AIDL_GENERATED_ANDROID_OS_I_PING_RESPONDER_H_
+)";
+
+const char kExpectedBpHeaderOutput[] =
+R"(#ifndef AIDL_GENERATED_ANDROID_OS_BP_PING_RESPONDER_H_
+#define AIDL_GENERATED_ANDROID_OS_BP_PING_RESPONDER_H_
+
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <utils/Errors.h>
+#include <android/os/IPingResponder.h>
+
+namespace android {
+
+namespace os {
+
+class BpPingResponder : public ::android::BpInterface<IPingResponder> {
+public:
+explicit BpPingResponder(const ::android::sp<::android::IBinder>& _aidl_impl);
+virtual ~BpPingResponder() = default;
+::android::binder::Status Ping(const ::android::String16& input, ::android::String16* _aidl_return) override;
+::android::binder::Status NullablePing(const ::std::unique_ptr<::android::String16>& input, ::std::unique_ptr<::android::String16>* _aidl_return) override;
+::android::binder::Status Utf8Ping(const ::std::string& input, ::std::string* _aidl_return) override;
+::android::binder::Status NullableUtf8Ping(const ::std::unique_ptr<::std::string>& input, ::std::unique_ptr<::std::string>* _aidl_return) override;
+};  // class BpPingResponder
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // AIDL_GENERATED_ANDROID_OS_BP_PING_RESPONDER_H_
+)";
+
+const char kExpectedBnHeaderOutput[] =
+R"(#ifndef AIDL_GENERATED_ANDROID_OS_BN_PING_RESPONDER_H_
+#define AIDL_GENERATED_ANDROID_OS_BN_PING_RESPONDER_H_
+
+#include <binder/IInterface.h>
+#include <android/os/IPingResponder.h>
+
+namespace android {
+
+namespace os {
+
+class BnPingResponder : public ::android::BnInterface<IPingResponder> {
+public:
+::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags = 0) override;
+};  // class BnPingResponder
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // AIDL_GENERATED_ANDROID_OS_BN_PING_RESPONDER_H_
+)";
+
+}  // namespace ping_responder
+}  // namespace test_data
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/test_data_string_constants.cpp b/aidl/tests/test_data_string_constants.cpp
new file mode 100644
index 0000000..4674843
--- /dev/null
+++ b/aidl/tests/test_data_string_constants.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tests/test_data.h"
+
+namespace android {
+namespace aidl {
+namespace test_data {
+namespace string_constants {
+
+const char kCanonicalName[] = "android.os.IStringConstants";
+const char kInterfaceDefinition[] = R"(
+package android.os;
+
+interface IStringConstants {
+  const String EXAMPLE_CONSTANT = "foo";
+}
+)";
+
+const char kJavaOutputPath[] = "some/path/to/output.java";
+const char kExpectedJavaOutput[] =
+R"(/*
+ * This file is auto-generated.  DO NOT MODIFY.
+ * Original file: android/os/IStringConstants.aidl
+ */
+package android.os;
+public interface IStringConstants extends android.os.IInterface
+{
+/** Local-side IPC implementation stub class. */
+public static abstract class Stub extends android.os.Binder implements android.os.IStringConstants
+{
+private static final java.lang.String DESCRIPTOR = "android.os.IStringConstants";
+/** Construct the stub at attach it to the interface. */
+public Stub()
+{
+this.attachInterface(this, DESCRIPTOR);
+}
+/**
+ * Cast an IBinder object into an android.os.IStringConstants interface,
+ * generating a proxy if needed.
+ */
+public static android.os.IStringConstants asInterface(android.os.IBinder obj)
+{
+if ((obj==null)) {
+return null;
+}
+android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+if (((iin!=null)&&(iin instanceof android.os.IStringConstants))) {
+return ((android.os.IStringConstants)iin);
+}
+return new android.os.IStringConstants.Stub.Proxy(obj);
+}
+@Override public android.os.IBinder asBinder()
+{
+return this;
+}
+@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
+{
+switch (code)
+{
+case INTERFACE_TRANSACTION:
+{
+reply.writeString(DESCRIPTOR);
+return true;
+}
+}
+return super.onTransact(code, data, reply, flags);
+}
+private static class Proxy implements android.os.IStringConstants
+{
+private android.os.IBinder mRemote;
+Proxy(android.os.IBinder remote)
+{
+mRemote = remote;
+}
+@Override public android.os.IBinder asBinder()
+{
+return mRemote;
+}
+public java.lang.String getInterfaceDescriptor()
+{
+return DESCRIPTOR;
+}
+}
+}
+public static final String EXAMPLE_CONSTANT = "foo";
+}
+)";
+
+const char kCppOutputPath[] = "some/path/to/output.cpp";
+const char kGenHeaderDir[] = "output";
+const char kGenInterfaceHeaderPath[] = "output/android/os/IStringConstants.h";
+const char kExpectedIHeaderOutput[] =
+R"(#ifndef AIDL_GENERATED_ANDROID_OS_I_STRING_CONSTANTS_H_
+#define AIDL_GENERATED_ANDROID_OS_I_STRING_CONSTANTS_H_
+
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <binder/Status.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace os {
+
+class IStringConstants : public ::android::IInterface {
+public:
+DECLARE_META_INTERFACE(StringConstants)
+static const ::android::String16& EXAMPLE_CONSTANT();
+};  // class IStringConstants
+
+}  // namespace os
+
+}  // namespace android
+
+#endif  // AIDL_GENERATED_ANDROID_OS_I_STRING_CONSTANTS_H_
+)";
+
+const char kExpectedCppOutput[] =
+R"(#include <android/os/IStringConstants.h>
+#include <android/os/BpStringConstants.h>
+
+namespace android {
+
+namespace os {
+
+IMPLEMENT_META_INTERFACE(StringConstants, "android.os.IStringConstants")
+
+const ::android::String16& IStringConstants::EXAMPLE_CONSTANT() {
+static const ::android::String16 value("foo");
+return value;
+}
+
+}  // namespace os
+
+}  // namespace android
+#include <android/os/BpStringConstants.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+BpStringConstants::BpStringConstants(const ::android::sp<::android::IBinder>& _aidl_impl)
+    : BpInterface<IStringConstants>(_aidl_impl){
+}
+
+}  // namespace os
+
+}  // namespace android
+#include <android/os/BnStringConstants.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+namespace os {
+
+::android::status_t BnStringConstants::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
+::android::status_t _aidl_ret_status = ::android::OK;
+switch (_aidl_code) {
+default:
+{
+_aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
+}
+break;
+}
+if (_aidl_ret_status == ::android::UNEXPECTED_NULL) {
+_aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply);
+}
+return _aidl_ret_status;
+}
+
+}  // namespace os
+
+}  // namespace android
+)";
+
+}  // namespace string_constants
+}  // namespace test_data
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/test_helpers.h b/aidl/tests/test_helpers.h
new file mode 100644
index 0000000..7d5145b
--- /dev/null
+++ b/aidl/tests/test_helpers.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
+
+#include "android/aidl/tests/ITestService.h"
+
+namespace android {
+namespace aidl {
+namespace tests {
+namespace client {
+
+template <typename T, typename U>
+bool RepeatPrimitive(
+    const android::sp<android::aidl::tests::ITestService>& service,
+    android::binder::Status(android::aidl::tests::ITestService::*func)(T, T*),
+    U input) {
+  T reply;
+  android::binder::Status status = (*service.*func)(input, &reply);
+  if (!status.isOk() || input != reply) {
+    LOG(ERROR) << "Failed to repeat primitive. status=" << status.toString8()
+               << ".";
+    return false;
+  }
+  return true;
+}
+
+template <typename T>
+bool ReverseArray(
+    const android::sp<android::aidl::tests::ITestService>& service,
+    android::binder::Status(android::aidl::tests::ITestService::*func)(
+        const std::vector<T>&, std::vector<T>*, std::vector<T>*),
+        std::vector<T> input) {
+  std::vector<T> actual_reversed;
+  std::vector<T> actual_repeated;
+  android::binder::Status status = (*service.*func)(
+      input, &actual_repeated, &actual_reversed);
+  if (!status.isOk()) {
+    LOG(ERROR) << "Failed to repeat array. status=" << status.toString8()
+               << ".";
+    return false;
+  }
+  if (input != actual_repeated) {
+    LOG(ERROR) << "Repeated version of array did not match";
+    LOG(ERROR) << "input.size()=" << input.size()
+               << " repeated.size()=" << actual_repeated.size();
+    return false;
+  }
+  std::reverse(input.begin(), input.end());
+  if (input != actual_reversed) {
+    LOG(ERROR) << "Reversed version of array did not match";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace client
+}  // namespace tests
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/tests/test_util.cpp b/aidl/tests/test_util.cpp
new file mode 100644
index 0000000..9cb52f3
--- /dev/null
+++ b/aidl/tests/test_util.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+
+#include <android-base/strings.h>
+
+#include "os.h"
+#include "tests/test_util.h"
+
+using android::base::Split;
+using android::base::Join;
+using std::string;
+using std::vector;
+using std::cout;
+using std::endl;
+using std::distance;
+
+namespace android {
+namespace aidl {
+namespace test {
+
+string CanonicalNameToPath(const char* package_class, const char* extension) {
+  string rel_path{package_class};
+  for (char& c : rel_path) {
+    if (c == '.') {
+      c = OS_PATH_SEPARATOR;
+    }
+  }
+  rel_path += extension;
+  return rel_path;
+}
+
+void SplitPackageClass(const string& package_class,
+                       string* rel_path,
+                       string* package,
+                       string* class_name) {
+  *package = string{package_class, 0, package_class.rfind('.')};
+  *class_name = string{package_class, package_class.rfind('.') + 1};
+  *rel_path = CanonicalNameToPath(package_class.c_str(), ".aidl");
+}
+
+void PrintDiff(const string& a, const string& b) {
+  const int LEFT = 1;
+  const int UP = 2;
+  const int UP_LEFT = 4;
+
+  auto a_lines = Split(a, "\n");
+  auto b_lines = Split(b, "\n");
+
+  struct diff_table_entry {
+    size_t longest_common_subsequence_length;
+    int propagation_directions;
+  };
+
+  diff_table_entry table[a_lines.size() + 1][b_lines.size() + 1];
+
+  for (size_t i = 0; i < a_lines.size() + 1; ++i) {
+    for (size_t j = 0; j < b_lines.size() + 1; ++j) {
+      if (i == 0 || j == 0) {
+        int directions = 0;
+
+        if (i) {
+          directions |= UP;
+        }
+
+        if (j) {
+          directions |= LEFT;
+        }
+
+        table[i][j].longest_common_subsequence_length = 0;
+        table[i][j].propagation_directions = directions;
+      } else if (a_lines[i-1] == b_lines[j-1]) {
+        table[i][j].longest_common_subsequence_length =
+            table[i-1][j-1].longest_common_subsequence_length + 1;
+        table[i][j].propagation_directions = UP_LEFT;
+      } else {
+        size_t length_up = table[i-1][j].longest_common_subsequence_length;
+        size_t length_left = table[i][j-1].longest_common_subsequence_length;
+        int directions = 0;
+        size_t length;
+
+        if (length_up >= length_left) {
+          directions |= UP;
+          length = length_up;
+        }
+
+        if (length_left >= length_up) {
+          directions |= LEFT;
+          length = length_left;
+        }
+
+        table[i][j].longest_common_subsequence_length = length;
+        table[i][j].propagation_directions = directions;
+      }
+    }
+  }
+
+  size_t i = a_lines.size();
+  size_t j = b_lines.size();
+  vector<string> output;
+
+  while (table[i][j].propagation_directions) {
+    if (table[i][j].propagation_directions & UP_LEFT) {
+      output.push_back(" " + a_lines[i-1]);
+      i--;
+      j--;
+    } else if (table[i][j].propagation_directions & UP) {
+      output.push_back("-" + a_lines[i-1]);
+      i--;
+    } else {
+      output.push_back("+" + b_lines[j-1]);
+      j--;
+    }
+  }
+
+  int print_mask = 0;
+  bool printed_last = false;
+  size_t line_number = 0;
+
+  for (auto it = output.crbegin(), frontier = output.crbegin();
+       it != output.crend(); ++it) {
+    while (frontier != output.crend() && distance(it, frontier) <= 3) {
+      print_mask <<= 1;
+      print_mask &= 0x7f;
+
+      if ((*frontier)[0] != ' ') {
+        print_mask |= 1;
+      }
+
+      frontier++;
+    }
+
+    if ((*it)[0] != '-') {
+      line_number++;
+    }
+
+    if (print_mask) {
+      if (!printed_last) {
+        cout << "Line: " << line_number << endl;
+      }
+
+      cout << *it << endl;
+      printed_last = true;
+    } else {
+      printed_last = false;
+    }
+  }
+}
+
+}  // namespace test
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/tests/test_util.h b/aidl/tests/test_util.h
new file mode 100644
index 0000000..34b9e5d
--- /dev/null
+++ b/aidl/tests/test_util.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_TESTS_TEST_UTIL_H_
+#define AIDL_TESTS_TEST_UTIL_H_
+
+#include <string>
+
+namespace android {
+namespace aidl {
+namespace test {
+
+std::string CanonicalNameToPath(const char* package_class,
+                                const char* extension);
+
+void SplitPackageClass(const std::string& package_class,
+                       std::string* rel_path,
+                       std::string* package,
+                       std::string* class_name);
+
+void PrintDiff(const std::string& a, const std::string& b);
+
+}  // namespace test
+}  // namespace android
+}  // namespace aidl
+
+#endif // AIDL_TESTS_TEST_UTIL_H_
diff --git a/aidl/type_cpp.cpp b/aidl/type_cpp.cpp
new file mode 100644
index 0000000..2c0552d
--- /dev/null
+++ b/aidl/type_cpp.cpp
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "type_cpp.h"
+
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "logging.h"
+
+using std::cerr;
+using std::endl;
+using std::set;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+using android::base::Split;
+using android::base::Join;
+using android::base::StringPrintf;
+
+namespace android {
+namespace aidl {
+namespace cpp {
+namespace {
+
+const char kNoPackage[] = "";
+const char kNoHeader[] = "";
+const char kNoValidMethod[] = "";
+Type* const kNoArrayType = nullptr;
+Type* const kNoNullableType = nullptr;
+
+bool is_cpp_keyword(const std::string& str) {
+  static const std::vector<std::string> kCppKeywords{
+    "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
+    "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
+    "compl", "concept", "const", "constexpr", "const_cast", "continue",
+    "decltype", "default", "delete", "do", "double", "dynamic_cast", "else",
+    "enum", "explicit", "export", "extern", "false", "float", "for", "friend",
+    "goto", "if", "inline", "int", "long", "mutable", "namespace", "new",
+    "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
+    "private", "protected", "public", "register", "reinterpret_cast",
+    "requires", "return", "short", "signed", "sizeof", "static",
+    "static_assert", "static_cast", "struct", "switch", "template", "this",
+    "thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
+    "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
+    "while", "xor", "xor_eq",
+  };
+  return std::find(kCppKeywords.begin(), kCppKeywords.end(), str) !=
+      kCppKeywords.end();
+}
+
+class VoidType : public Type {
+ public:
+  VoidType() : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "void",
+                    {}, "void", kNoValidMethod, kNoValidMethod) {}
+  virtual ~VoidType() = default;
+  bool CanBeOutParameter() const override { return false; }
+  bool CanWriteToParcel() const override { return false; }
+};  // class VoidType
+
+class CppArrayType : public Type {
+ public:
+  CppArrayType(int kind,  // from ValidatableType
+            const std::string& package,
+            const string& underlying_aidl_type,
+            const string& cpp_header,
+            const string& underlying_cpp_type,
+            const string& read_method,
+            const string& write_method,
+            bool is_nullable,
+            const string& src_file_name = "")
+      : Type(kind, package,
+             underlying_aidl_type + "[]",
+             GetHeaders(is_nullable, cpp_header),
+             GetCppType(is_nullable, underlying_cpp_type),
+             read_method, write_method, kNoArrayType,
+             (is_nullable)
+                 ? kNoNullableType
+                 // All arrays are nullable.
+                 : new CppArrayType(kind, package, underlying_aidl_type,
+                                    cpp_header, underlying_cpp_type,
+                                    read_method, write_method, true),
+             src_file_name) {}
+
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  static vector<string> GetHeaders(bool is_nullable, const string& cpp_header) {
+    vector<string> result = {"vector"};
+    if (is_nullable) {
+      result.push_back("memory");
+    }
+    if (!cpp_header.empty()) {
+      result.push_back(cpp_header);
+    }
+    return result;
+  }
+
+  static string GetCppType(bool is_nullable,
+                           const string& underlying_cpp_type) {
+    if (is_nullable)
+      return StringPrintf("::std::unique_ptr<::std::vector<%s>>",
+                          underlying_cpp_type.c_str());
+    return StringPrintf("::std::vector<%s>",
+                        underlying_cpp_type.c_str());
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(CppArrayType);
+};  // class CppArrayType
+
+class PrimitiveType : public Type {
+ public:
+  PrimitiveType(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(ValidatableType::KIND_BUILT_IN, kNoPackage, aidl_type, {header},
+             cpp_type, read_method, write_method,
+             new CppArrayType(ValidatableType::KIND_BUILT_IN, kNoPackage,
+                              aidl_type, header, cpp_type,
+                              read_array_method, write_array_method,
+                              false)) {}
+
+  virtual ~PrimitiveType() = default;
+  bool IsCppPrimitive() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrimitiveType);
+};  // class PrimitiveType
+
+// Unfortunately, bytes in Java are signed.  However, most C authors would
+// say that a byte is not in fact signed.  Compromise: customize this otherwise
+// normal primitive to use signed single bytes, but unsigned byte arrays.
+class ByteType : public Type {
+ public:
+  ByteType()
+      : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "byte",
+             {"cstdint"}, "int8_t", "readByte", "writeByte",
+             new CppArrayType(ValidatableType::KIND_BUILT_IN, kNoPackage,
+                              "byte", "cstdint", "uint8_t",
+                              "readByteVector", "writeByteVector",
+                              false)) {}
+
+  virtual ~ByteType() = default;
+  bool IsCppPrimitive() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ByteType);
+};  // class PrimitiveType
+
+class BinderType : public Type {
+ public:
+  BinderType(const AidlInterface& interface, const std::string& src_file_name)
+      : BinderType(interface, src_file_name,
+                   new BinderType(interface, src_file_name, kNoNullableType,
+                                  "readNullableStrongBinder"),
+                   "readStrongBinder") {}
+  virtual ~BinderType() = default;
+
+  string WriteCast(const string& val) const override {
+    return write_cast_ + "(" + val + ")";
+  }
+
+ private:
+  BinderType(const AidlInterface& interface,
+             const std::string& src_file_name,
+             Type* nullable_type, const std::string& read)
+      : Type(ValidatableType::KIND_GENERATED,
+             interface.GetPackage(), interface.GetName(),
+             {GetCppHeader(interface)}, GetCppName(interface),
+             read, "writeStrongBinder", kNoArrayType, nullable_type,
+             src_file_name, interface.GetLine()),
+        write_cast_(GetRawCppName(interface) + "::asBinder") {}
+
+  static string GetCppName(const AidlInterface& interface) {
+    return "::android::sp<" + GetRawCppName(interface) + ">";
+  }
+
+  static string GetRawCppName(const AidlInterface& interface) {
+    vector<string> name = interface.GetSplitPackage();
+    string ret;
+
+    name.push_back(interface.GetName());
+
+    for (const auto& term : name) {
+      ret += "::" + term;
+    }
+
+    return ret;
+  }
+
+  static string GetCppHeader(const AidlInterface& interface) {
+    vector<string> name = interface.GetSplitPackage();
+    name.push_back(interface.GetName());
+    return Join(name, '/') + ".h";
+  }
+
+  std::string write_cast_;
+};
+
+class NullableParcelableType : public Type {
+ public:
+  NullableParcelableType(const AidlParcelable& parcelable,
+                         const std::string& src_file_name)
+      : Type(ValidatableType::KIND_PARCELABLE,
+             parcelable.GetPackage(), parcelable.GetName(),
+             {parcelable.GetCppHeader()}, GetCppName(parcelable),
+             "readParcelable", "writeNullableParcelable",
+             kNoArrayType, kNoNullableType,
+             src_file_name, parcelable.GetLine()) {}
+  virtual ~NullableParcelableType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  static string GetCppName(const AidlParcelable& parcelable) {
+    return "::std::unique_ptr<::" + 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),
+             "readParcelable", "writeParcelable",
+             new CppArrayType(
+                 ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(),
+                 parcelable.GetName(), parcelable.GetCppHeader(),
+                 GetCppName(parcelable),
+                 "readParcelableVector", "writeParcelableVector", false,
+                 src_file_name),
+             new NullableParcelableType(parcelable, src_file_name),
+             src_file_name, parcelable.GetLine()) {}
+  virtual ~ParcelableType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  static string GetCppName(const AidlParcelable& parcelable) {
+    return "::" + Join(parcelable.GetSplitPackage(), "::") +
+        "::" + parcelable.GetName();
+  }
+};
+
+class NullableStringListType : public Type {
+ public:
+  NullableStringListType()
+      : Type(ValidatableType::KIND_BUILT_IN,
+             "java.util", "List<" + string(kStringCanonicalName) + ">",
+             {"utils/String16.h", "memory", "vector"},
+             "::std::unique_ptr<::std::vector<std::unique_ptr<::android::String16>>>",
+             "readString16Vector", "writeString16Vector") {}
+  virtual ~NullableStringListType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NullableStringListType);
+};  // class NullableStringListType
+
+class StringListType : public Type {
+ public:
+  StringListType()
+      : Type(ValidatableType::KIND_BUILT_IN,
+             "java.util", "List<" + string(kStringCanonicalName) + ">",
+             {"utils/String16.h", "vector"},
+             "::std::vector<::android::String16>",
+             "readString16Vector", "writeString16Vector",
+             kNoArrayType, new NullableStringListType()) {}
+  virtual ~StringListType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StringListType);
+};  // class StringListType
+
+class NullableUtf8InCppStringListType : public Type {
+ public:
+  NullableUtf8InCppStringListType()
+      : Type(ValidatableType::KIND_BUILT_IN,
+             "java.util", "List<" + string(kUtf8InCppStringCanonicalName) + ">",
+             {"memory", "string", "vector"},
+             "::std::unique_ptr<::std::vector<std::unique_ptr<::std::string>>>",
+             "readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector") {}
+  virtual ~NullableUtf8InCppStringListType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NullableUtf8InCppStringListType);
+};  // class NullableUtf8InCppStringListType
+
+class Utf8InCppStringListType : public Type {
+ public:
+  Utf8InCppStringListType()
+      : Type(ValidatableType::KIND_BUILT_IN,
+             "java.util", "List<" + string(kUtf8InCppStringCanonicalName) + ">",
+             {"string", "vector"},
+             "::std::vector<::std::string>",
+             "readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector",
+             kNoArrayType, new NullableUtf8InCppStringListType()) {}
+  virtual ~Utf8InCppStringListType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Utf8InCppStringListType);
+};  // class Utf8InCppStringListType
+
+class NullableBinderListType : public Type {
+ public:
+  NullableBinderListType()
+      : Type(ValidatableType::KIND_BUILT_IN, "java.util",
+             "List<android.os.IBinder>", {"binder/IBinder.h", "vector"},
+             "::std::unique_ptr<::std::vector<::android::sp<::android::IBinder>>>",
+             "readStrongBinderVector", "writeStrongBinderVector") {}
+  virtual ~NullableBinderListType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NullableBinderListType);
+};  // class NullableBinderListType
+
+class BinderListType : public Type {
+ public:
+  BinderListType()
+      : Type(ValidatableType::KIND_BUILT_IN, "java.util",
+             "List<android.os.IBinder>", {"binder/IBinder.h", "vector"},
+             "::std::vector<::android::sp<::android::IBinder>>",
+             "readStrongBinderVector", "writeStrongBinderVector",
+             kNoArrayType, new NullableBinderListType()) {}
+  virtual ~BinderListType() = default;
+  bool CanBeOutParameter() const override { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BinderListType);
+};  // class BinderListType
+
+}  // namespace
+
+Type::Type(int kind,
+           const std::string& package,
+           const std::string& aidl_type,
+           const vector<string>& headers,
+           const string& cpp_type,
+           const string& read_method,
+           const string& write_method,
+           Type* array_type,
+           Type* nullable_type,
+           const string& src_file_name,
+           int line)
+    : ValidatableType(kind, package, aidl_type, src_file_name, line),
+      headers_(headers),
+      aidl_type_(aidl_type),
+      cpp_type_(cpp_type),
+      parcel_read_method_(read_method),
+      parcel_write_method_(write_method),
+      array_type_(array_type),
+      nullable_type_(nullable_type) {}
+
+bool Type::CanWriteToParcel() const { return true; }
+
+void TypeNamespace::Init() {
+  Add(new ByteType());
+  Add(new PrimitiveType(
+      "int",
+      "cstdint", "int32_t", "readInt32", "writeInt32",
+      "readInt32Vector", "writeInt32Vector"));
+  Add(new PrimitiveType(
+      "long",
+      "cstdint", "int64_t", "readInt64", "writeInt64",
+      "readInt64Vector", "writeInt64Vector"));
+  Add(new PrimitiveType(
+      "float",
+      kNoHeader, "float", "readFloat", "writeFloat",
+      "readFloatVector", "writeFloatVector"));
+  Add(new PrimitiveType(
+      "double",
+      kNoHeader, "double", "readDouble", "writeDouble",
+      "readDoubleVector", "writeDoubleVector"));
+  Add(new PrimitiveType(
+      "boolean",
+      kNoHeader, "bool", "readBool", "writeBool",
+      "readBoolVector", "writeBoolVector"));
+  // C++11 defines the char16_t type as a built in for Unicode characters.
+  Add(new PrimitiveType(
+      "char",
+      kNoHeader, "char16_t", "readChar", "writeChar",
+      "readCharVector", "writeCharVector"));
+
+  Type* string_array_type = new CppArrayType(
+      ValidatableType::KIND_BUILT_IN, "java.lang", "String",
+      "utils/String16.h", "::android::String16",
+      "readString16Vector", "writeString16Vector", false);
+
+  Type* nullable_string_type =
+      new Type(ValidatableType::KIND_BUILT_IN, "java.lang", "String",
+               {"memory", "utils/String16.h"}, "::std::unique_ptr<::android::String16>",
+               "readString16", "writeString16");
+
+  string_type_ = new Type(ValidatableType::KIND_BUILT_IN, "java.lang", "String",
+                          {"utils/String16.h"}, "::android::String16",
+                          "readString16", "writeString16",
+                          string_array_type, nullable_string_type);
+  Add(string_type_);
+
+  using ::android::aidl::kAidlReservedTypePackage;
+  using ::android::aidl::kUtf8InCppStringClass;
+
+  // This type is a Utf16 string in the parcel, but deserializes to
+  // a std::string in Utf8 format when we use it in C++.
+  Type* cpp_utf8_string_array = new CppArrayType(
+      ValidatableType::KIND_BUILT_IN,
+      kAidlReservedTypePackage, kUtf8InCppStringClass,
+      "string", "::std::string",
+      "readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector",
+      false);
+  Type* nullable_cpp_utf8_string_type = new Type(
+      ValidatableType::KIND_BUILT_IN,
+      kAidlReservedTypePackage, kUtf8InCppStringClass,
+      {"string", "memory"}, "::std::unique_ptr<::std::string>",
+      "readUtf8FromUtf16", "writeUtf8AsUtf16");
+  Add(new Type(
+      ValidatableType::KIND_BUILT_IN,
+      kAidlReservedTypePackage, kUtf8InCppStringClass,
+      {"string"}, "::std::string", "readUtf8FromUtf16", "writeUtf8AsUtf16",
+      cpp_utf8_string_array, nullable_cpp_utf8_string_type));
+
+  Type* nullable_ibinder = new Type(
+      ValidatableType::KIND_BUILT_IN, "android.os", "IBinder",
+      {"binder/IBinder.h"}, "::android::sp<::android::IBinder>",
+      "readNullableStrongBinder", "writeStrongBinder");
+  ibinder_type_ = new Type(
+      ValidatableType::KIND_BUILT_IN, "android.os", "IBinder",
+      {"binder/IBinder.h"}, "::android::sp<::android::IBinder>",
+      "readStrongBinder", "writeStrongBinder",
+      kNoArrayType, nullable_ibinder);
+  Add(ibinder_type_);
+
+  Add(new BinderListType());
+  Add(new StringListType());
+  Add(new Utf8InCppStringListType());
+
+  Type* fd_vector_type = new CppArrayType(
+      ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor",
+      "android-base/unique_fd.h",
+      "::android::base::unique_fd",
+      "readUniqueFileDescriptorVector", "writeUniqueFileDescriptorVector",
+      false);
+
+  Add(new Type(
+      ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor",
+      {"android-base/unique_fd.h"}, "::android::base::unique_fd",
+      "readUniqueFileDescriptor", "writeUniqueFileDescriptor",
+      fd_vector_type));
+
+  void_type_ = new class VoidType();
+  Add(void_type_);
+}
+
+bool TypeNamespace::AddParcelableType(const AidlParcelable& p,
+                                      const string& filename) {
+  if (p.GetCppHeader().empty()) {
+    LOG(ERROR) << "Parcelable " << p.GetCanonicalName()
+               << " has no C++ header defined.";
+    return false;
+  }
+  Add(new ParcelableType(p, filename));
+  return true;
+}
+
+bool TypeNamespace::AddBinderType(const AidlInterface& b,
+                                  const string& file_name) {
+  Add(new BinderType(b, file_name));
+  return true;
+}
+
+bool TypeNamespace::AddListType(const std::string& type_name) {
+  const Type* contained_type = FindTypeByCanonicalName(type_name);
+  if (!contained_type) {
+    LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
+                  "type cannot be found or is invalid.";
+    return false;
+  }
+  if (contained_type->IsCppPrimitive()) {
+    LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
+                  "type is a primitive in Java and Java List cannot hold "
+                  "primitives.";
+    return false;
+  }
+
+  if (contained_type->CanonicalName() == kStringCanonicalName ||
+      contained_type->CanonicalName() == kUtf8InCppStringCanonicalName ||
+      contained_type == IBinderType()) {
+    return true;
+  }
+
+  // TODO Support lists of parcelables b/23600712
+
+  LOG(ERROR) << "aidl-cpp does not yet support List<" << type_name << ">";
+  return false;
+}
+
+bool TypeNamespace::AddMapType(const std::string& /* key_type_name */,
+                               const std::string& /* value_type_name */) {
+  // TODO Support list types b/25242025
+  LOG(ERROR) << "aidl does not implement support for typed maps!";
+  return false;
+}
+
+bool TypeNamespace::IsValidPackage(const string& package) const {
+  if (package.empty()) {
+    return false;
+  }
+
+  auto pieces = Split(package, ".");
+  for (const string& piece : pieces) {
+    if (is_cpp_keyword(piece)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a,
+    int arg_index,
+    const std::string& filename,
+    const AidlInterface& interface) const {
+  const string error_prefix = StringPrintf(
+      "In file %s line %d parameter %s (%d):\n    ",
+      filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
+
+  // check that the name doesn't match a keyword
+  if (is_cpp_keyword(a.GetName().c_str())) {
+    cerr << error_prefix << "Argument name is a C++ keyword"
+         << endl;
+    return nullptr;
+  }
+
+  return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, filename,
+                                                    interface);
+}
+
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/type_cpp.h b/aidl/type_cpp.h
new file mode 100644
index 0000000..0a6a4a9
--- /dev/null
+++ b/aidl/type_cpp.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_TYPE_CPP_H_
+#define AIDL_TYPE_CPP_H_
+
+#include <memory>
+#include <string>
+#include <set>
+#include <vector>
+
+#include <android-base/macros.h>
+
+#include "type_namespace.h"
+
+namespace android {
+namespace aidl {
+namespace cpp {
+
+class Type : public ValidatableType {
+ public:
+  Type(int kind,  // from ValidatableType
+       const std::string& package,
+       const std::string& aidl_type,
+       const std::vector<std::string>& header,
+       const std::string& cpp_type,
+       const std::string& read_method,
+       const std::string& write_method,
+       Type* array_type = nullptr,
+       Type* nullable_type = nullptr,
+       const std::string& src_file_name = "",
+       int line = -1);
+  virtual ~Type() = default;
+
+  // overrides of ValidatableType
+  bool CanBeOutParameter() const override { return false; }
+  bool CanWriteToParcel() const override;
+
+  const Type* ArrayType() const override { return array_type_.get(); }
+  const Type* NullableType() const override { return nullable_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 (const 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:
+  // |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::unique_ptr<Type> array_type_;
+  const std::unique_ptr<Type> nullable_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(Type);
+};  // class Type
+
+class TypeNamespace : public ::android::aidl::LanguageTypeNamespace<Type> {
+ public:
+  TypeNamespace() = default;
+  virtual ~TypeNamespace() = default;
+
+  void Init() override;
+  bool AddParcelableType(const AidlParcelable& p,
+                         const std::string& filename) override;
+  bool AddBinderType(const AidlInterface& b,
+                     const std::string& filename) override;
+  bool AddListType(const std::string& type_name) override;
+  bool AddMapType(const std::string& key_type_name,
+                  const std::string& value_type_name) override;
+
+  bool IsValidPackage(const std::string& package) const override;
+  const ValidatableType* GetArgType(const AidlArgument& a,
+                             int arg_index,
+                             const std::string& filename,
+                             const AidlInterface& interface) const override;
+
+  const Type* VoidType() const { return void_type_; }
+  const Type* IBinderType() const { return ibinder_type_; }
+
+ private:
+  Type* void_type_ = nullptr;
+  Type* string_type_ = nullptr;
+  Type* ibinder_type_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
+};  // class TypeNamespace
+
+}  // namespace cpp
+}  // namespace aidl
+}  // namespace android
+
+#endif  // AIDL_TYPE_NAMESPACE_CPP_H_
diff --git a/aidl/type_cpp_unittest.cpp b/aidl/type_cpp_unittest.cpp
new file mode 100644
index 0000000..35fc3d5
--- /dev/null
+++ b/aidl/type_cpp_unittest.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "type_cpp.h"
+
+namespace android {
+namespace aidl {
+namespace cpp {
+
+class CppTypeNamespaceTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    types_.Init();
+  }
+  TypeNamespace types_;
+};
+
+TEST_F(CppTypeNamespaceTest, HasSomeBasicTypes) {
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("byte"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("int"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("long"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("float"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("double"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("boolean"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("char"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("String"));
+}
+
+TEST_F(CppTypeNamespaceTest, SupportsListString) {
+  EXPECT_TRUE(
+      types_.HasTypeByCanonicalName("java.util.List<java.lang.String>"));
+}
+
+}  // namespace cpp
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/type_java.cpp b/aidl/type_java.cpp
new file mode 100644
index 0000000..18d27a2
--- /dev/null
+++ b/aidl/type_java.cpp
@@ -0,0 +1,908 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "type_java.h"
+
+#include <sys/types.h>
+
+#include <android-base/strings.h>
+
+#include "aidl_language.h"
+#include "logging.h"
+
+using std::string;
+using android::base::Split;
+using android::base::Join;
+using android::base::Trim;
+
+namespace android {
+namespace aidl {
+namespace java {
+
+Expression* NULL_VALUE;
+Expression* THIS_VALUE;
+Expression* SUPER_VALUE;
+Expression* TRUE_VALUE;
+Expression* FALSE_VALUE;
+
+// ================================================================
+
+Type::Type(const JavaTypeNamespace* types, const string& name, int kind,
+           bool canWriteToParcel, bool canBeOut)
+    : Type(types, "", name, kind, canWriteToParcel, canBeOut, "", -1) {}
+
+Type::Type(const JavaTypeNamespace* types, const string& package,
+           const string& name, int kind, bool canWriteToParcel,
+           bool canBeOut, const string& declFile, int declLine)
+    : ValidatableType(kind, package, name, declFile, declLine),
+      m_types(types),
+      m_javaType((package.empty()) ? name : package + "." + name),
+      m_canWriteToParcel(canWriteToParcel),
+      m_canBeOut(canBeOut) {
+}
+
+string Type::CreatorName() const { return ""; }
+
+string Type::InstantiableName() const { return JavaType(); }
+
+void Type::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                         int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn", __FILE__,
+          __LINE__, m_javaType.c_str());
+  addTo->Add(new LiteralExpression("/* WriteToParcel error " + m_javaType +
+                                   " */"));
+}
+
+void Type::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", __FILE__,
+          __LINE__, m_javaType.c_str());
+  addTo->Add(new LiteralExpression("/* CreateFromParcel error " +
+                                   m_javaType + " */"));
+}
+
+void Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                          Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", __FILE__,
+          __LINE__, m_javaType.c_str());
+  addTo->Add(new LiteralExpression("/* ReadFromParcel error " +
+                                   m_javaType + " */"));
+}
+
+Expression* Type::BuildWriteToParcelFlags(int flags) const {
+  if (flags == 0) {
+    return new LiteralExpression("0");
+  }
+  if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+    return new FieldVariable(m_types->ParcelableInterfaceType(),
+                             "PARCELABLE_WRITE_RETURN_VALUE");
+  }
+  return new LiteralExpression("0");
+}
+
+// ================================================================
+
+BasicType::BasicType(const JavaTypeNamespace* types, const string& name,
+                     const string& marshallParcel,
+                     const string& unmarshallParcel,
+                     const string& writeArrayParcel,
+                     const string& createArrayParcel,
+                     const string& readArrayParcel)
+    : Type(types, name, ValidatableType::KIND_BUILT_IN, true, false),
+      m_marshallParcel(marshallParcel),
+      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 {
+  addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
+}
+
+void BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                 Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
+}
+
+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, true),
+      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 BasicArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                      Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
+}
+
+void BasicArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable**) const {
+  addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
+}
+
+// ================================================================
+
+FileDescriptorType::FileDescriptorType(const JavaTypeNamespace* types)
+    : Type(types, "java.io", "FileDescriptor", ValidatableType::KIND_BUILT_IN,
+           true, false) {
+    m_array_type.reset(new FileDescriptorArrayType(types));
+}
+
+void FileDescriptorType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                       Variable* parcel, int flags) const {
+  addTo->Add(new MethodCall(parcel, "writeRawFileDescriptor", 1, v));
+}
+
+void FileDescriptorType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                          Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "readRawFileDescriptor")));
+}
+
+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 FileDescriptorArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                               Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "createRawFileDescriptorArray")));
+}
+
+void FileDescriptorArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                             Variable* parcel, Variable**) const {
+  addTo->Add(new MethodCall(parcel, "readRawFileDescriptorArray", 1, v));
+}
+
+// ================================================================
+
+BooleanType::BooleanType(const JavaTypeNamespace* types)
+    : 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 {
+  addTo->Add(new MethodCall(
+      parcel, "writeInt", 1,
+      new Ternary(v, new LiteralExpression("1"), new LiteralExpression("0"))));
+}
+
+void BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                   Variable* parcel, Variable**) const {
+  addTo->Add(
+      new Assignment(v, new Comparison(new LiteralExpression("0"), "!=",
+                                       new MethodCall(parcel, "readInt"))));
+}
+
+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 BooleanArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                        Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
+}
+
+void BooleanArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                      Variable* parcel, Variable**) const {
+  addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
+}
+
+// ================================================================
+
+CharType::CharType(const JavaTypeNamespace* types)
+    : 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 {
+  addTo->Add(
+      new MethodCall(parcel, "writeInt", 1, new Cast(m_types->IntType(), v)));
+}
+
+void CharType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
+}
+
+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 CharArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                     Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
+}
+
+void CharArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                   Variable* parcel, Variable**) const {
+  addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
+}
+
+// ================================================================
+
+StringType::StringType(const JavaTypeNamespace* types,
+                       const std::string& package,
+                       const std::string& class_name)
+    : Type(types, package, class_name,
+           ValidatableType::KIND_BUILT_IN, true, false) {
+  m_array_type.reset(new StringArrayType(types));
+}
+
+string StringType::CreatorName() const {
+  return "android.os.Parcel.STRING_CREATOR";
+}
+
+void StringType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                               Variable* parcel, int flags) const {
+  addTo->Add(new MethodCall(parcel, "writeString", 1, v));
+}
+
+void StringType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                  Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
+}
+
+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 StringArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                       Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
+}
+
+void StringArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                     Variable* parcel, Variable**) const {
+  addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
+}
+
+// ================================================================
+
+CharSequenceType::CharSequenceType(const JavaTypeNamespace* types)
+    : Type(types, "java.lang", "CharSequence", ValidatableType::KIND_BUILT_IN,
+           true, false) {}
+
+string CharSequenceType::CreatorName() const {
+  return "android.os.Parcel.STRING_CREATOR";
+}
+
+void CharSequenceType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                     Variable* parcel, int flags) const {
+  // if (v != null) {
+  //     parcel.writeInt(1);
+  //     v.writeToParcel(parcel);
+  // } else {
+  //     parcel.writeInt(0);
+  // }
+  IfStatement* elsepart = new IfStatement();
+  elsepart->statements->Add(
+      new MethodCall(parcel, "writeInt", 1, new LiteralExpression("0")));
+  IfStatement* ifpart = new IfStatement;
+  ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
+  ifpart->elseif = elsepart;
+  ifpart->statements->Add(
+      new MethodCall(parcel, "writeInt", 1, new LiteralExpression("1")));
+  ifpart->statements->Add(new MethodCall(m_types->TextUtilsType(),
+                                         "writeToParcel", 3, v, parcel,
+                                         BuildWriteToParcelFlags(flags)));
+
+  addTo->Add(ifpart);
+}
+
+void CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                        Variable* parcel, Variable**) const {
+  // if (0 != parcel.readInt()) {
+  //     v = TextUtils.createFromParcel(parcel)
+  // } else {
+  //     v = null;
+  // }
+  IfStatement* elsepart = new IfStatement();
+  elsepart->statements->Add(new Assignment(v, NULL_VALUE));
+
+  IfStatement* ifpart = new IfStatement();
+  ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                                      new MethodCall(parcel, "readInt"));
+  ifpart->elseif = elsepart;
+  ifpart->statements->Add(new Assignment(
+      v, new MethodCall(m_types->TextUtilsType(),
+                        "CHAR_SEQUENCE_CREATOR.createFromParcel", 1, parcel)));
+
+  addTo->Add(ifpart);
+}
+
+// ================================================================
+
+RemoteExceptionType::RemoteExceptionType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "RemoteException",
+           ValidatableType::KIND_BUILT_IN, false, false) {}
+
+void RemoteExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                        Variable* parcel, int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                           Variable* parcel, Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+RuntimeExceptionType::RuntimeExceptionType(const JavaTypeNamespace* types)
+    : Type(types, "java.lang", "RuntimeException",
+           ValidatableType::KIND_BUILT_IN, false, false) {}
+
+void RuntimeExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                         Variable* parcel, int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                            Variable* parcel,
+                                            Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+IBinderType::IBinderType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "IBinder", ValidatableType::KIND_BUILT_IN,
+           true, false) {
+  m_array_type.reset(new IBinderArrayType(types));
+}
+
+void IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                Variable* parcel, int flags) const {
+  addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, v));
+}
+
+void IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                   Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
+}
+
+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 IBinderArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                        Variable* parcel, Variable**) const {
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
+}
+
+void IBinderArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                      Variable* parcel, Variable**) const {
+  addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
+}
+
+// ================================================================
+
+IInterfaceType::IInterfaceType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "IInterface", ValidatableType::KIND_BUILT_IN,
+           false, false) {}
+
+void IInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                   Variable* parcel, int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                      Variable* parcel, Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+BinderType::BinderType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "Binder", ValidatableType::KIND_BUILT_IN,
+           false, false) {}
+
+void BinderType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                               Variable* parcel, int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                  Variable* parcel, Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+BinderProxyType::BinderProxyType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "BinderProxy", ValidatableType::KIND_BUILT_IN,
+           false, false) {}
+
+void BinderProxyType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                       Variable* parcel, Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+ParcelType::ParcelType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "Parcel", ValidatableType::KIND_BUILT_IN,
+           false, false) {}
+
+void ParcelType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                               Variable* parcel, int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                  Variable* parcel, Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+ParcelableInterfaceType::ParcelableInterfaceType(const JavaTypeNamespace* types)
+    : Type(types, "android.os", "Parcelable", ValidatableType::KIND_BUILT_IN,
+           false, false) {}
+
+void ParcelableInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                            Variable* parcel, int flags) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+void ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo,
+                                               Variable* v, Variable* parcel,
+                                               Variable**) const {
+  fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
+}
+
+// ================================================================
+
+MapType::MapType(const JavaTypeNamespace* types)
+    : Type(types, "java.util", "Map", ValidatableType::KIND_BUILT_IN,
+           true, true) {}
+
+void MapType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                            Variable* parcel, int flags) const {
+  addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
+}
+
+static void EnsureClassLoader(StatementBlock* addTo, Variable** cl,
+                              const JavaTypeNamespace* types) {
+  // We don't want to look up the class loader once for every
+  // collection argument, so ensure we do it at most once per method.
+  if (*cl == NULL) {
+    *cl = new Variable(types->ClassLoaderType(), "cl");
+    addTo->Add(new VariableDeclaration(
+        *cl, new LiteralExpression("this.getClass().getClassLoader()"),
+        types->ClassLoaderType()));
+  }
+}
+
+void MapType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                               Variable* parcel, Variable** cl) const {
+  EnsureClassLoader(addTo, cl, m_types);
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, *cl)));
+}
+
+void MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                             Variable* parcel, Variable** cl) const {
+  EnsureClassLoader(addTo, cl, m_types);
+  addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
+}
+
+// ================================================================
+
+ListType::ListType(const JavaTypeNamespace* types)
+    : Type(types, "java.util", "List", ValidatableType::KIND_BUILT_IN,
+           true, true) {}
+
+string ListType::InstantiableName() const { return "java.util.ArrayList"; }
+
+void ListType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                             Variable* parcel, int flags) const {
+  addTo->Add(new MethodCall(parcel, "writeList", 1, v));
+}
+
+void ListType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                Variable* parcel, Variable** cl) const {
+  EnsureClassLoader(addTo, cl, m_types);
+  addTo->Add(
+      new Assignment(v, new MethodCall(parcel, "readArrayList", 1, *cl)));
+}
+
+void ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                              Variable* parcel, Variable** cl) const {
+  EnsureClassLoader(addTo, cl, m_types);
+  addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
+}
+
+// ================================================================
+
+UserDataType::UserDataType(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) {
+  m_array_type.reset(new UserDataArrayType(types, package, name, builtIn,
+                                           canWriteToParcel, declFile,
+                                           declLine));
+}
+
+string UserDataType::CreatorName() const {
+  return JavaType() + ".CREATOR";
+}
+
+void UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                 Variable* parcel, int flags) const {
+  // if (v != null) {
+  //     parcel.writeInt(1);
+  //     v.writeToParcel(parcel);
+  // } else {
+  //     parcel.writeInt(0);
+  // }
+  IfStatement* elsepart = new IfStatement();
+  elsepart->statements->Add(
+      new MethodCall(parcel, "writeInt", 1, new LiteralExpression("0")));
+  IfStatement* ifpart = new IfStatement;
+  ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
+  ifpart->elseif = elsepart;
+  ifpart->statements->Add(
+      new MethodCall(parcel, "writeInt", 1, new LiteralExpression("1")));
+  ifpart->statements->Add(new MethodCall(v, "writeToParcel", 2, parcel,
+                                         BuildWriteToParcelFlags(flags)));
+
+  addTo->Add(ifpart);
+}
+
+void UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, Variable**) const {
+  // if (0 != parcel.readInt()) {
+  //     v = CLASS.CREATOR.createFromParcel(parcel)
+  // } else {
+  //     v = null;
+  // }
+  IfStatement* elsepart = new IfStatement();
+  elsepart->statements->Add(new Assignment(v, NULL_VALUE));
+
+  IfStatement* ifpart = new IfStatement();
+  ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                                      new MethodCall(parcel, "readInt"));
+  ifpart->elseif = elsepart;
+  ifpart->statements->Add(new Assignment(
+      v, new MethodCall(v->type, "CREATOR.createFromParcel", 1, parcel)));
+
+  addTo->Add(ifpart);
+}
+
+void UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                  Variable* parcel, Variable**) const {
+  // TODO: really, we don't need to have this extra check, but we
+  // don't have two separate marshalling code paths
+  // if (0 != parcel.readInt()) {
+  //     v.readFromParcel(parcel)
+  // }
+  IfStatement* ifpart = new IfStatement();
+  ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
+                                      new MethodCall(parcel, "readInt"));
+  ifpart->statements->Add(new MethodCall(v, "readFromParcel", 1, parcel));
+  addTo->Add(ifpart);
+}
+
+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 JavaType() + ".CREATOR";
+}
+
+void UserDataArrayType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                      Variable* parcel, int flags) const {
+  addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
+                            BuildWriteToParcelFlags(flags)));
+}
+
+void UserDataArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                         Variable* parcel, Variable**) const {
+  string creator = v->type->JavaType() + ".CREATOR";
+  addTo->Add(new Assignment(v, new MethodCall(parcel, "createTypedArray", 1,
+                                              new LiteralExpression(creator))));
+}
+
+void UserDataArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                       Variable* parcel, Variable**) const {
+  string creator = v->type->JavaType() + ".CREATOR";
+  addTo->Add(new MethodCall(parcel, "readTypedArray", 2, v,
+                            new LiteralExpression(creator)));
+}
+
+// ================================================================
+
+InterfaceType::InterfaceType(const JavaTypeNamespace* types,
+                             const string& package, const string& name,
+                             bool builtIn, bool oneway, const string& declFile,
+                             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),
+      stub_(stub),
+      proxy_(proxy) {}
+
+bool InterfaceType::OneWay() const { return m_oneway; }
+
+void InterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                  Variable* parcel, int flags) const {
+  // parcel.writeStrongBinder(v != null ? v.asBinder() : null);
+  addTo->Add(
+      new MethodCall(parcel, "writeStrongBinder", 1,
+                     new Ternary(new Comparison(v, "!=", NULL_VALUE),
+                                 new MethodCall(v, "asBinder"), NULL_VALUE)));
+}
+
+void InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                     Variable* parcel, Variable**) const {
+  // v = Interface.asInterface(parcel.readStrongBinder());
+  addTo->Add(new Assignment(
+      v, new MethodCall(stub_, "asInterface", 1,
+                        new MethodCall(parcel, "readStrongBinder"))));
+}
+
+// ================================================================
+
+GenericListType::GenericListType(const JavaTypeNamespace* types,
+                                 const Type* contained_type)
+    : Type(types, "java.util", "List<" + contained_type->CanonicalName() + ">",
+           ValidatableType::KIND_BUILT_IN, true, true),
+      m_contained_type(contained_type),
+      m_creator(contained_type->CreatorName()) {}
+
+string GenericListType::CreatorName() const {
+  return "android.os.Parcel.arrayListCreator";
+}
+
+string GenericListType::InstantiableName() const {
+  return "java.util.ArrayList<" + m_contained_type->JavaType() + ">";
+}
+
+void GenericListType::WriteToParcel(StatementBlock* addTo, Variable* v,
+                                    Variable* parcel, int flags) const {
+  if (m_creator == m_types->StringType()->CreatorName()) {
+    addTo->Add(new MethodCall(parcel, "writeStringList", 1, v));
+  } else if (m_creator == m_types->IBinderType()->CreatorName()) {
+    addTo->Add(new MethodCall(parcel, "writeBinderList", 1, v));
+  } else {
+    // parcel.writeTypedListXX(arg);
+    addTo->Add(new MethodCall(parcel, "writeTypedList", 1, v));
+  }
+}
+
+void GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                       Variable* parcel, Variable**) const {
+  if (m_creator == m_types->StringType()->CreatorName()) {
+    addTo->Add(
+        new Assignment(v, new MethodCall(parcel, "createStringArrayList", 0)));
+  } else if (m_creator == m_types->IBinderType()->CreatorName()) {
+    addTo->Add(
+        new Assignment(v, new MethodCall(parcel, "createBinderArrayList", 0)));
+  } else {
+    // v = _data.readTypedArrayList(XXX.creator);
+    addTo->Add(
+        new Assignment(v, new MethodCall(parcel, "createTypedArrayList", 1,
+                                         new LiteralExpression(m_creator))));
+  }
+}
+
+void GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+                                     Variable* parcel, Variable**) const {
+  if (m_creator == m_types->StringType()->CreatorName()) {
+    addTo->Add(new MethodCall(parcel, "readStringList", 1, v));
+  } else if (m_creator == m_types->IBinderType()->CreatorName()) {
+    addTo->Add(new MethodCall(parcel, "readBinderList", 1, v));
+  } else {
+    // v = _data.readTypedList(v, XXX.creator);
+    addTo->Add(new MethodCall(parcel, "readTypedList", 2, v,
+                              new LiteralExpression(m_creator)));
+  }
+}
+
+// ================================================================
+
+ClassLoaderType::ClassLoaderType(const JavaTypeNamespace* types)
+    : Type(types, "java.lang", "ClassLoader", ValidatableType::KIND_BUILT_IN,
+           false, false) {}
+
+// ================================================================
+
+void JavaTypeNamespace::Init() {
+  Add(new BasicType(this, "void", "XXX", "XXX", "XXX", "XXX", "XXX"));
+
+  m_bool_type = new BooleanType(this);
+  Add(m_bool_type);
+
+  Add(new BasicType(this, "byte", "writeByte", "readByte", "writeByteArray",
+                    "createByteArray", "readByteArray"));
+
+  Add(new CharType(this));
+
+  m_int_type = new BasicType(this, "int", "writeInt", "readInt",
+                             "writeIntArray", "createIntArray", "readIntArray");
+  Add(m_int_type);
+
+  Add(new BasicType(this, "long", "writeLong", "readLong", "writeLongArray",
+                    "createLongArray", "readLongArray"));
+
+  Add(new BasicType(this, "float", "writeFloat", "readFloat", "writeFloatArray",
+                    "createFloatArray", "readFloatArray"));
+
+  Add(new BasicType(this, "double", "writeDouble", "readDouble",
+                    "writeDoubleArray", "createDoubleArray",
+                    "readDoubleArray"));
+
+  m_string_type = new class StringType(this, "java.lang", "String");
+  Add(m_string_type);
+  Add(new class StringType(this, ::android::aidl::kAidlReservedTypePackage,
+                           ::android::aidl::kUtf8InCppStringClass));
+
+  Add(new Type(this, "java.lang", "Object", ValidatableType::KIND_BUILT_IN,
+               false, false));
+
+  Add(new FileDescriptorType(this));
+
+  Add(new CharSequenceType(this));
+
+  Add(new MapType(this));
+
+  Add(new ListType(this));
+
+  m_text_utils_type =
+      new Type(this, "android.text", "TextUtils",
+               ValidatableType::KIND_BUILT_IN, false, false);
+  Add(m_text_utils_type);
+
+  m_remote_exception_type = new class RemoteExceptionType(this);
+  Add(m_remote_exception_type);
+
+  m_runtime_exception_type = new class RuntimeExceptionType(this);
+  Add(m_runtime_exception_type);
+
+  m_ibinder_type = new class IBinderType(this);
+  Add(m_ibinder_type);
+
+  m_iinterface_type = new class IInterfaceType(this);
+  Add(m_iinterface_type);
+
+  m_binder_native_type = new class BinderType(this);
+  Add(m_binder_native_type);
+
+  m_binder_proxy_type = new class BinderProxyType(this);
+  Add(m_binder_proxy_type);
+
+  m_parcel_type = new class ParcelType(this);
+  Add(m_parcel_type);
+
+  m_parcelable_interface_type = new class ParcelableInterfaceType(this);
+  Add(m_parcelable_interface_type);
+
+  m_context_type = new class Type(this, "android.content", "Context",
+                                  ValidatableType::KIND_BUILT_IN, false, false);
+  Add(m_context_type);
+
+  m_classloader_type = new class ClassLoaderType(this);
+  Add(m_classloader_type);
+
+  NULL_VALUE = new LiteralExpression("null");
+  THIS_VALUE = new LiteralExpression("this");
+  SUPER_VALUE = new LiteralExpression("super");
+  TRUE_VALUE = new LiteralExpression("true");
+  FALSE_VALUE = new LiteralExpression("false");
+}
+
+bool JavaTypeNamespace::AddParcelableType(const AidlParcelable& p,
+                                          const std::string& filename) {
+  Type* type =
+      new UserDataType(this, p.GetPackage(), p.GetName(), false,
+                       true, filename, p.GetLine());
+  return Add(type);
+}
+
+bool JavaTypeNamespace::AddBinderType(const AidlInterface& b,
+                                      const std::string& filename) {
+  // for interfaces, add the stub, proxy, and interface types.
+  Type* stub = new Type(this, b.GetPackage(),
+                        b.GetName() + ".Stub", ValidatableType::KIND_GENERATED,
+                        false, false, filename, b.GetLine());
+  Type* proxy = new Type(this, b.GetPackage(),
+                         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);
+  success &= Add(stub);
+  success &= Add(proxy);
+  return success;
+}
+
+bool JavaTypeNamespace::AddListType(const std::string& contained_type_name) {
+  const Type* contained_type = FindTypeByCanonicalName(contained_type_name);
+  if (!contained_type) {
+    return false;
+  }
+  Add(new GenericListType(this, contained_type));
+  return true;
+}
+
+bool JavaTypeNamespace::AddMapType(const string& key_type_name,
+                                   const string& value_type_name) {
+  LOG(ERROR) << "Don't know how to create a Map<K,V> container.";
+  return false;
+}
+
+}  // namespace java
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/type_java.h b/aidl/type_java.h
new file mode 100644
index 0000000..6d35f2a
--- /dev/null
+++ b/aidl/type_java.h
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_TYPE_JAVA_H_
+#define AIDL_TYPE_JAVA_H_
+
+#include <string>
+#include <vector>
+
+#include "ast_java.h"
+#include "type_namespace.h"
+
+namespace android {
+namespace aidl {
+namespace java {
+
+class JavaTypeNamespace;
+
+class Type : public ValidatableType {
+ public:
+  // WriteToParcel flags
+  enum { PARCELABLE_WRITE_RETURN_VALUE = 0x0001 };
+
+  Type(const JavaTypeNamespace* types, const std::string& name, int kind,
+       bool canWriteToParcel, bool canBeOut);
+  Type(const JavaTypeNamespace* types, const std::string& package,
+       const std::string& name, int kind, bool canWriteToParcel, bool canBeOut,
+       const std::string& declFile = "", int declLine = -1);
+  virtual ~Type() = default;
+
+  bool CanBeOutParameter() const override { return m_canBeOut; }
+  bool CanWriteToParcel() const override { return m_canWriteToParcel; }
+
+  const ValidatableType* ArrayType() const override { return m_array_type.get(); }
+  const ValidatableType* NullableType() const override { return nullptr; }
+
+  virtual std::string JavaType() const { return m_javaType; }
+  virtual std::string CreatorName() const;
+  virtual std::string InstantiableName() const;
+
+  virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
+                             Variable* parcel, int flags) const;
+  virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
+                                Variable* parcel, Variable** cl) const;
+  virtual void ReadFromParcel(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&);
+
+  std::string m_javaType;
+  std::string m_declFile;
+  bool m_canWriteToParcel;
+  bool m_canBeOut;
+};
+
+class BasicArrayType : public Type {
+ public:
+  BasicArrayType(const JavaTypeNamespace* types, const std::string& name,
+                 const std::string& writeArrayParcel,
+                 const std::string& createArrayParcel,
+                 const std::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;
+  const ValidatableType* NullableType() const override { return this; }
+
+ private:
+  std::string m_writeArrayParcel;
+  std::string m_createArrayParcel;
+  std::string m_readArrayParcel;
+};
+
+class BasicType : public Type {
+ public:
+  BasicType(const JavaTypeNamespace* types, const std::string& name,
+            const std::string& marshallParcel,
+            const std::string& unmarshallParcel,
+            const std::string& writeArrayParcel,
+            const std::string& createArrayParcel,
+            const std::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;
+
+ private:
+  std::string m_marshallParcel;
+  std::string m_unmarshallParcel;
+};
+
+class FileDescriptorArrayType : public Type {
+ public:
+  explicit 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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class FileDescriptorType : public Type {
+ public:
+  explicit FileDescriptorType(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;
+};
+
+class BooleanArrayType : public Type {
+ public:
+  explicit BooleanArrayType(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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class BooleanType : public Type {
+ public:
+  explicit BooleanType(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;
+};
+
+class CharArrayType : public Type {
+ public:
+  explicit CharArrayType(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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class CharType : public Type {
+ public:
+  explicit CharType(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;
+};
+
+class StringArrayType : public Type {
+ public:
+  explicit StringArrayType(const JavaTypeNamespace* types);
+
+  std::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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class StringType : public Type {
+ public:
+  StringType(const JavaTypeNamespace* types, const std::string& package,
+             const std::string& class_name);
+
+  std::string JavaType() const override { return "java.lang.String"; }
+  std::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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class CharSequenceType : public Type {
+ public:
+  explicit CharSequenceType(const JavaTypeNamespace* types);
+
+  std::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;
+};
+
+class RemoteExceptionType : public Type {
+ public:
+  explicit RemoteExceptionType(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;
+};
+
+class RuntimeExceptionType : public Type {
+ public:
+  explicit RuntimeExceptionType(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;
+};
+
+class IBinderArrayType : public Type {
+ public:
+  explicit 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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class IBinderType : public Type {
+ public:
+  explicit IBinderType(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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class IInterfaceType : public Type {
+ public:
+  explicit IInterfaceType(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;
+};
+
+class BinderType : public Type {
+ public:
+  explicit BinderType(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;
+};
+
+class BinderProxyType : public Type {
+ public:
+  explicit BinderProxyType(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;
+};
+
+class ParcelType : public Type {
+ public:
+  explicit ParcelType(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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class ParcelableInterfaceType : public Type {
+ public:
+  explicit ParcelableInterfaceType(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;
+};
+
+class MapType : public Type {
+ public:
+  explicit MapType(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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class ListType : public Type {
+ public:
+  explicit ListType(const JavaTypeNamespace* types);
+
+  std::string InstantiableName() 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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class UserDataArrayType : public Type {
+ public:
+  UserDataArrayType(const JavaTypeNamespace* types, const std::string& package,
+                    const std::string& name, bool builtIn,
+                    bool canWriteToParcel, const std::string& declFile = "",
+                    int declLine = -1);
+
+  std::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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class UserDataType : public Type {
+ public:
+  UserDataType(const JavaTypeNamespace* types, const std::string& package,
+               const std::string& name, bool builtIn, bool canWriteToParcel,
+               const std::string& declFile = "", int declLine = -1);
+
+  std::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;
+  const ValidatableType* NullableType() const override { return this; }
+};
+
+class InterfaceType : public Type {
+ public:
+  InterfaceType(const JavaTypeNamespace* types, const std::string& package,
+                const std::string& name, bool builtIn, bool oneway,
+                const std::string& declFile, int declLine, const Type* stub,
+                const Type* proxy);
+
+  bool OneWay() const;
+
+  void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                     int flags) const override;
+  void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel,
+                        Variable** cl) const override;
+  const ValidatableType* NullableType() const override { return this; }
+  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 {
+ public:
+  explicit ClassLoaderType(const JavaTypeNamespace* types);
+};
+
+class GenericListType : public Type {
+ public:
+  GenericListType(const JavaTypeNamespace* types, const Type* arg);
+
+  std::string CreatorName() const override;
+  std::string InstantiableName() const override;
+  std::string JavaType() const override {
+    return "java.util.List<" + m_contained_type->JavaType() + ">";
+  }
+
+  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;
+  const ValidatableType* NullableType() const override { return this; }
+
+ private:
+  const Type* m_contained_type;
+  const std::string m_creator;
+};
+
+class JavaTypeNamespace : public LanguageTypeNamespace<Type> {
+ public:
+  JavaTypeNamespace() = default;
+  virtual ~JavaTypeNamespace() = default;
+
+  void Init() override;
+  bool AddParcelableType(const AidlParcelable& p,
+                         const std::string& filename) override;
+  bool AddBinderType(const AidlInterface& b,
+                     const std::string& filename) override;
+  bool AddListType(const std::string& contained_type_name) override;
+  bool AddMapType(const std::string& key_type_name,
+                  const std::string& value_type_name) override;
+
+  const Type* BoolType() const { return m_bool_type; }
+  const Type* IntType() const { return m_int_type; }
+  const Type* StringType() const { return m_string_type; }
+  const Type* TextUtilsType() const { return m_text_utils_type; }
+  const Type* RemoteExceptionType() const { return m_remote_exception_type; }
+  const Type* RuntimeExceptionType() const { return m_runtime_exception_type; }
+  const Type* IBinderType() const { return m_ibinder_type; }
+  const Type* IInterfaceType() const { return m_iinterface_type; }
+  const Type* BinderNativeType() const { return m_binder_native_type; }
+  const Type* BinderProxyType() const { return m_binder_proxy_type; }
+  const Type* ParcelType() const { return m_parcel_type; }
+  const Type* ParcelableInterfaceType() const {
+    return m_parcelable_interface_type;
+  }
+  const Type* ContextType() const { return m_context_type; }
+  const Type* ClassLoaderType() const { return m_classloader_type; }
+
+ private:
+  const Type* m_bool_type{nullptr};
+  const Type* m_int_type{nullptr};
+  const Type* m_string_type{nullptr};
+  const Type* m_text_utils_type{nullptr};
+  const Type* m_remote_exception_type{nullptr};
+  const Type* m_runtime_exception_type{nullptr};
+  const Type* m_ibinder_type{nullptr};
+  const Type* m_iinterface_type{nullptr};
+  const Type* m_binder_native_type{nullptr};
+  const Type* m_binder_proxy_type{nullptr};
+  const Type* m_parcel_type{nullptr};
+  const Type* m_parcelable_interface_type{nullptr};
+  const Type* m_context_type{nullptr};
+  const Type* m_classloader_type{nullptr};
+
+  DISALLOW_COPY_AND_ASSIGN(JavaTypeNamespace);
+};
+
+extern Expression* NULL_VALUE;
+extern Expression* THIS_VALUE;
+extern Expression* SUPER_VALUE;
+extern Expression* TRUE_VALUE;
+extern Expression* FALSE_VALUE;
+
+}  // namespace java
+}  // namespace aidl
+}  // namespace android
+
+#endif  // AIDL_TYPE_JAVA_H_
diff --git a/aidl/type_java_unittest.cpp b/aidl/type_java_unittest.cpp
new file mode 100644
index 0000000..a9df134
--- /dev/null
+++ b/aidl/type_java_unittest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "aidl_language.h"
+#include "type_java.h"
+
+using std::unique_ptr;
+
+namespace android {
+namespace aidl {
+namespace java {
+
+class JavaTypeNamespaceTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    types_.Init();
+  }
+  JavaTypeNamespace types_;
+};
+
+TEST_F(JavaTypeNamespaceTest, HasSomeBasicTypes) {
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("void"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("int"));
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("java.lang.String"));
+}
+
+TEST_F(JavaTypeNamespaceTest, ContainerTypeCreation) {
+  // We start with no knowledge of parcelables or lists of them.
+  EXPECT_FALSE(types_.HasTypeByCanonicalName("Foo"));
+  EXPECT_FALSE(types_.HasTypeByCanonicalName("java.util.List<a.goog.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_TRUE(types_.HasTypeByCanonicalName("a.goog.Foo"));
+  EXPECT_FALSE(types_.HasTypeByCanonicalName("java.util.List<a.goog.Foo>"));
+  // But after we add the list explicitly...
+  AidlType container_type("List<Foo>", 0, "", false /* not array */);
+  EXPECT_TRUE(types_.MaybeAddContainerType(container_type));
+  // This should work.
+  EXPECT_TRUE(types_.HasTypeByCanonicalName("java.util.List<a.goog.Foo>"));
+}
+
+}  // namespace java
+}  // namespace android
+}  // namespace aidl
diff --git a/aidl/type_namespace.cpp b/aidl/type_namespace.cpp
new file mode 100644
index 0000000..d3f4aaf
--- /dev/null
+++ b/aidl/type_namespace.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "type_namespace.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "aidl_language.h"
+#include "logging.h"
+
+using android::base::StringPrintf;
+using android::base::Split;
+using android::base::Trim;
+using std::string;
+using std::vector;
+
+namespace android {
+namespace aidl {
+
+// Since packages cannot contain '-' normally, we cannot be asked
+// to create a type that conflicts with these strings.
+const char kAidlReservedTypePackage[] = "aidl-internal";
+const char kUtf8StringClass[] = "Utf8String";
+const char kUtf8InCppStringClass[] = "Utf8InCppString";
+
+// These *must* match the package and class names above.
+const char kUtf8StringCanonicalName[] = "aidl-internal.Utf8String";
+const char kUtf8InCppStringCanonicalName[] = "aidl-internal.Utf8InCppString";
+
+const char kStringCanonicalName[] = "java.lang.String";
+
+const char kUtf8Annotation[] = "@utf8";
+const char kUtf8InCppAnnotation[] = "@utfInCpp";
+
+namespace {
+
+bool is_java_keyword(const char* str) {
+  static const std::vector<std::string> kJavaKeywords{
+      "abstract",   "assert",       "boolean",   "break",      "byte",
+      "case",       "catch",        "char",      "class",      "const",
+      "continue",   "default",      "do",        "double",     "else",
+      "enum",       "extends",      "final",     "finally",    "float",
+      "for",        "goto",         "if",        "implements", "import",
+      "instanceof", "int",          "interface", "long",       "native",
+      "new",        "package",      "private",   "protected",  "public",
+      "return",     "short",        "static",    "strictfp",   "super",
+      "switch",     "synchronized", "this",      "throw",      "throws",
+      "transient",  "try",          "void",      "volatile",   "while",
+      "true",       "false",        "null",
+  };
+  return std::find(kJavaKeywords.begin(), kJavaKeywords.end(), str) !=
+      kJavaKeywords.end();
+}
+
+} // namespace
+
+ValidatableType::ValidatableType(
+    int kind, const string& package, const string& type_name,
+    const string& decl_file, int decl_line)
+    : kind_(kind),
+      type_name_(type_name),
+      canonical_name_((package.empty()) ? type_name
+                                        : package + "." + type_name),
+      origin_file_(decl_file),
+      origin_line_(decl_line) {}
+
+string ValidatableType::HumanReadableKind() const {
+  switch (Kind()) {
+    case ValidatableType::KIND_BUILT_IN:
+      return "a built in";
+    case ValidatableType::KIND_PARCELABLE:
+      return "a parcelable";
+    case ValidatableType::KIND_INTERFACE:
+      return "an interface";
+    case ValidatableType::KIND_GENERATED:
+      return "a generated";
+  }
+  return "unknown";
+}
+
+bool TypeNamespace::IsValidPackage(const string& /* package */) const {
+  return true;
+}
+
+const ValidatableType* TypeNamespace::GetReturnType(
+    const AidlType& raw_type, const string& filename,
+    const AidlInterface& interface) const {
+  string error_msg;
+  const ValidatableType* return_type = GetValidatableType(raw_type, &error_msg,
+                                                          interface);
+  if (return_type == nullptr) {
+    LOG(ERROR) << StringPrintf("In file %s line %d return type %s:\n    ",
+                               filename.c_str(), raw_type.GetLine(),
+                               raw_type.ToString().c_str())
+               << error_msg;
+    return nullptr;
+  }
+
+  return return_type;
+}
+
+const ValidatableType* TypeNamespace::GetArgType(
+    const AidlArgument& a, int arg_index, const string& filename,
+    const AidlInterface& interface) const {
+  string error_prefix = StringPrintf(
+      "In file %s line %d parameter %s (argument %d):\n    ",
+      filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
+
+  // check the arg type
+  string error_msg;
+  const ValidatableType* t = GetValidatableType(a.GetType(), &error_msg,
+                                                interface);
+  if (t == nullptr) {
+    LOG(ERROR) << error_prefix << error_msg;
+    return nullptr;
+  }
+
+  if (!a.DirectionWasSpecified() && t->CanBeOutParameter()) {
+    LOG(ERROR) << error_prefix << StringPrintf(
+        "'%s' can be an out type, so you must declare it as in,"
+        " out or inout.",
+        a.GetType().ToString().c_str());
+    return nullptr;
+  }
+
+  if (a.GetDirection() != AidlArgument::IN_DIR &&
+      !t->CanBeOutParameter()) {
+    LOG(ERROR) << error_prefix << StringPrintf(
+        "'%s' can only be an in parameter.",
+        a.ToString().c_str());
+    return nullptr;
+  }
+
+  // check that the name doesn't match a keyword
+  if (is_java_keyword(a.GetName().c_str())) {
+    LOG(ERROR) << error_prefix << "Argument name is a Java or aidl keyword";
+    return nullptr;
+  }
+
+  // Reserve a namespace for internal use
+  if (a.GetName().substr(0, 5)  == "_aidl") {
+    LOG(ERROR) << error_prefix << "Argument name cannot begin with '_aidl'";
+    return nullptr;
+  }
+
+  return t;
+}
+
+}  // namespace aidl
+}  // namespace android
diff --git a/aidl/type_namespace.h b/aidl/type_namespace.h
new file mode 100644
index 0000000..7defd24
--- /dev/null
+++ b/aidl/type_namespace.h
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AIDL_TYPE_NAMESPACE_H_
+#define AIDL_TYPE_NAMESPACE_H_
+
+#include <memory>
+#include <string>
+
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "aidl_language.h"
+#include "logging.h"
+
+namespace android {
+namespace aidl {
+
+// Special reserved type names.
+extern const char kAidlReservedTypePackage[];
+extern const char kUtf8StringClass[];  // UTF8 wire format string
+extern const char kUtf8InCppStringClass[];  // UTF16 wire format, UTF8 in C++
+
+// Helpful aliases defined to be <kAidlReservedTypePackage>.<class name>
+extern const char kUtf8StringCanonicalName[];
+extern const char kUtf8InCppStringCanonicalName[];
+
+// We sometimes special case this class.
+extern const char kStringCanonicalName[];
+
+// Note that these aren't the strings recognized by the parser, we just keep
+// here for the sake of logging a common string constant.
+extern const char kUtf8Annotation[];
+extern const char kUtf8InCppAnnotation[];
+
+class ValidatableType {
+ public:
+  enum {
+    KIND_BUILT_IN,
+    KIND_PARCELABLE,
+    KIND_INTERFACE,
+    KIND_GENERATED,
+  };
+
+  ValidatableType(int kind,
+                  const std::string& package, const std::string& type_name,
+                  const std::string& decl_file, int decl_line);
+  virtual ~ValidatableType() = default;
+
+  virtual bool CanBeArray() const { return ArrayType() != nullptr; }
+  virtual bool CanBeOutParameter() const = 0;
+  virtual bool CanWriteToParcel() const = 0;
+
+  virtual const ValidatableType* ArrayType() const = 0;
+  virtual const ValidatableType* NullableType() const = 0;
+
+  // ShortName() is the class name without a package.
+  std::string ShortName() const { return type_name_; }
+  // CanonicalName() returns the canonical AIDL type, with packages.
+  std::string CanonicalName() const { return canonical_name_; }
+
+  int Kind() const { return kind_; }
+  std::string HumanReadableKind() const;
+  std::string DeclFile() const { return origin_file_; }
+  int DeclLine() const { return origin_line_; }
+
+ private:
+  const int kind_;
+  const std::string type_name_;
+  const std::string canonical_name_;
+  const std::string origin_file_;
+  const int origin_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValidatableType);
+};
+
+class TypeNamespace {
+ public:
+  // Load the TypeNamespace with built in types.  Don't do work in the
+  // constructor because many of the useful methods are virtual.
+  virtual void Init() = 0;
+
+  // Load this TypeNamespace with user defined types.
+  virtual bool AddParcelableType(const AidlParcelable& p,
+                                 const std::string& filename) = 0;
+  virtual bool AddBinderType(const AidlInterface& b,
+                             const std::string& filename) = 0;
+  // Add a container type to this namespace.  Returns false only
+  // on error. Silently discards requests to add non-container types.
+  virtual bool MaybeAddContainerType(const AidlType& aidl_type) = 0;
+
+  // Returns true iff this has a type for |import|.
+  virtual bool HasImportType(const AidlImport& import) const = 0;
+
+  // Returns true iff |package| is a valid package name.
+  virtual bool IsValidPackage(const std::string& package) const;
+
+  // Returns a pointer to a type corresponding to |raw_type| or nullptr
+  // if this is an invalid return type.
+  virtual const ValidatableType* GetReturnType(
+      const AidlType& raw_type,
+      const std::string& filename,
+      const AidlInterface& interface) const;
+
+  // Returns a pointer to a type corresponding to |a| or nullptr if |a|
+  // has an invalid argument type.
+  virtual const ValidatableType* GetArgType(
+      const AidlArgument& a,
+      int arg_index,
+      const std::string& filename,
+      const AidlInterface& interface) const;
+
+  // Returns a pointer to a type corresponding to |interface|.
+  virtual const ValidatableType* GetInterfaceType(
+      const AidlInterface& interface) const = 0;
+
+ protected:
+  TypeNamespace() = default;
+  virtual ~TypeNamespace() = default;
+
+  virtual const ValidatableType* GetValidatableType(
+      const AidlType& type, std::string* error_msg,
+      const AidlInterface& interface) const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
+};
+
+template<typename T>
+class LanguageTypeNamespace : public TypeNamespace {
+ public:
+  LanguageTypeNamespace() = default;
+  virtual ~LanguageTypeNamespace() = default;
+
+  // Get a pointer to an existing type.  Searches first by fully-qualified
+  // name, and then class name (dropping package qualifiers).
+  const T* Find(const AidlType& aidl_type) const;
+
+  // Find a type by its |name|.  If |name| refers to a container type (e.g.
+  // List<String>) you must turn it into a canonical name first (e.g.
+  // java.util.List<java.lang.String>).
+  const T* FindTypeByCanonicalName(const std::string& name) const;
+  bool HasTypeByCanonicalName(const std::string& type_name) const {
+    return FindTypeByCanonicalName(type_name) != nullptr;
+  }
+  bool HasImportType(const AidlImport& import) const override {
+    return HasTypeByCanonicalName(import.GetNeededClass());
+  }
+  const ValidatableType* GetInterfaceType(
+      const AidlInterface& interface) const override {
+    return FindTypeByCanonicalName(interface.GetCanonicalName());
+  }
+
+  bool MaybeAddContainerType(const AidlType& aidl_type) override;
+  // We dynamically create container types as we discover them in the parse
+  // tree.  Returns false if the contained types cannot be canonicalized.
+  virtual bool AddListType(const std::string& contained_type_name) = 0;
+  virtual bool AddMapType(const std::string& key_type_name,
+                          const std::string& value_type_name) = 0;
+
+ protected:
+  bool Add(const T* type);
+
+ private:
+  // Returns true iff the name can be canonicalized to a container type.
+  virtual bool CanonicalizeContainerType(
+      const AidlType& aidl_type,
+      std::vector<std::string>* container_class,
+      std::vector<std::string>* contained_type_names) const;
+
+  // Returns true if this is a container type, rather than a normal type.
+  bool IsContainerType(const std::string& type_name) const;
+
+  const ValidatableType* GetValidatableType(
+      const AidlType& type, std::string* error_msg,
+      const AidlInterface& interface) const override;
+
+  std::vector<std::unique_ptr<const T>> types_;
+
+  DISALLOW_COPY_AND_ASSIGN(LanguageTypeNamespace);
+};  // class LanguageTypeNamespace
+
+template<typename T>
+bool LanguageTypeNamespace<T>::Add(const T* type) {
+  const T* existing = FindTypeByCanonicalName(type->CanonicalName());
+  if (!existing) {
+    types_.emplace_back(type);
+    return true;
+  }
+
+  if (existing->Kind() == ValidatableType::KIND_BUILT_IN) {
+    LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine()
+               << " attempt to redefine built in class "
+               << type->CanonicalName();
+    return false;
+  }
+
+  if (type->Kind() != existing->Kind()) {
+    LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine()
+               << " attempt to redefine " << type->CanonicalName()
+               << " as " << type->HumanReadableKind();
+    LOG(ERROR) << existing->DeclFile() << ":" << existing->DeclLine()
+               << " previously defined here as "
+               << existing->HumanReadableKind();
+    return false;
+  }
+
+  return true;
+}
+
+template<typename T>
+const T* LanguageTypeNamespace<T>::Find(const AidlType& aidl_type) const {
+  using std::string;
+  using std::vector;
+  using android::base::Join;
+  using android::base::Trim;
+
+  string name = Trim(aidl_type.GetName());
+  if (IsContainerType(name)) {
+    vector<string> container_class;
+    vector<string> contained_type_names;
+    if (!CanonicalizeContainerType(aidl_type, &container_class,
+                                   &contained_type_names)) {
+      return nullptr;
+    }
+    name = Join(container_class, '.') +
+           "<" + Join(contained_type_names, ',') + ">";
+  }
+  // Here, we know that we have the canonical name for this container.
+  return FindTypeByCanonicalName(name);
+}
+
+template<typename T>
+const T* LanguageTypeNamespace<T>::FindTypeByCanonicalName(
+    const std::string& raw_name) const {
+  using android::base::Trim;
+
+  std::string name = Trim(raw_name);
+  const T* ret = nullptr;
+  for (const auto& type : types_) {
+    // Always prefer a exact match if possible.
+    // This works for primitives and class names qualified with a package.
+    if (type->CanonicalName() == name) {
+      ret = type.get();
+      break;
+    }
+    // We allow authors to drop packages when refering to a class name.
+    if (type->ShortName() == name) {
+      ret = type.get();
+    }
+  }
+
+  return ret;
+}
+
+template<typename T>
+bool LanguageTypeNamespace<T>::MaybeAddContainerType(
+    const AidlType& aidl_type) {
+  using android::base::Join;
+
+  const std::string& type_name = aidl_type.GetName();
+  if (!IsContainerType(type_name)) {
+    return true;
+  }
+
+  std::vector<std::string> container_class;
+  std::vector<std::string> contained_type_names;
+  if (!CanonicalizeContainerType(aidl_type, &container_class,
+                                 &contained_type_names)) {
+    return false;
+  }
+
+  const std::string canonical_name = Join(container_class, ".") +
+      "<" + Join(contained_type_names, ",") + ">";
+  if (HasTypeByCanonicalName(canonical_name)) {
+    return true;
+  }
+
+
+  // We only support two types right now and this type is one of them.
+  switch (contained_type_names.size()) {
+    case 1:
+      return AddListType(contained_type_names[0]);
+    case 2:
+      return AddMapType(contained_type_names[0], contained_type_names[1]);
+    default:
+      break;  // Should never get here, will FATAL below.
+  }
+
+  LOG(FATAL) << "aidl internal error";
+  return false;
+}
+
+template<typename T>
+bool LanguageTypeNamespace<T>::IsContainerType(
+    const std::string& type_name) const {
+  const size_t opening_brace = type_name.find('<');
+  const size_t closing_brace = type_name.find('>');
+  if (opening_brace != std::string::npos ||
+      closing_brace != std::string::npos) {
+    return true;  // Neither < nor > appear in normal AIDL types.
+  }
+  return false;
+}
+
+template<typename T>
+bool LanguageTypeNamespace<T>::CanonicalizeContainerType(
+    const AidlType& aidl_type,
+    std::vector<std::string>* container_class,
+    std::vector<std::string>* contained_type_names) const {
+  using android::base::Trim;
+  using android::base::Split;
+
+  std::string name = Trim(aidl_type.GetName());
+  const size_t opening_brace = name.find('<');
+  const size_t closing_brace = name.find('>');
+  if (opening_brace == std::string::npos ||
+      closing_brace == std::string::npos) {
+    return false;
+  }
+
+  if (opening_brace != name.rfind('<') ||
+      closing_brace != name.rfind('>') ||
+      closing_brace != name.length() - 1) {
+    // Nested/invalid templates are forbidden.
+    LOG(ERROR) << "Invalid template type '" << name << "'";
+    return false;
+  }
+
+  std::string container = Trim(name.substr(0, opening_brace));
+  std::string remainder = name.substr(opening_brace + 1,
+                                 (closing_brace - opening_brace) - 1);
+  std::vector<std::string> args = Split(remainder, ",");
+  for (auto& type_name: args) {
+    // Here, we are relying on FindTypeByCanonicalName to do its best when
+    // given a non-canonical name for non-compound type (i.e. not another
+    // container).
+    const T* arg_type = FindTypeByCanonicalName(type_name);
+    if (!arg_type) {
+      return false;
+    }
+
+    // Now get the canonical names for these contained types, remapping them if
+    // necessary.
+    type_name = arg_type->CanonicalName();
+    if (aidl_type.IsUtf8() && type_name == "java.lang.String") {
+      type_name = kUtf8StringCanonicalName;
+    } else if (aidl_type.IsUtf8InCpp() && type_name == "java.lang.String") {
+      type_name = kUtf8InCppStringCanonicalName;
+    }
+  }
+
+  // Map the container name to its canonical form for supported containers.
+  if ((container == "List" || container == "java.util.List") &&
+      args.size() == 1) {
+    *container_class = {"java", "util", "List"};
+    *contained_type_names = args;
+    return true;
+  }
+  if ((container == "Map" || container == "java.util.Map") &&
+      args.size() == 2) {
+    *container_class = {"java", "util", "Map"};
+    *contained_type_names = args;
+    return true;
+  }
+
+  LOG(ERROR) << "Unknown find container with name " << container
+             << " and " << args.size() << "contained types.";
+  return false;
+}
+
+template<typename T>
+const ValidatableType* LanguageTypeNamespace<T>::GetValidatableType(
+    const AidlType& aidl_type, std::string* error_msg,
+    const AidlInterface& interface) const {
+  using android::base::StringPrintf;
+
+  const ValidatableType* type = Find(aidl_type);
+  if (type == nullptr) {
+    *error_msg = "unknown type";
+    return nullptr;
+  }
+
+  if (aidl_type.GetName() == "void") {
+    if (aidl_type.IsArray()) {
+      *error_msg = "void type cannot be an array";
+      return nullptr;
+    }
+    if (aidl_type.IsNullable() || aidl_type.IsUtf8() ||
+        aidl_type.IsUtf8InCpp()) {
+      *error_msg = "void type cannot be annotated";
+      return nullptr;
+    }
+    // We have no more special handling for void.
+    return type;
+  }
+
+  // No type may be annotated with both these annotations.
+  if (aidl_type.IsUtf8() && aidl_type.IsUtf8InCpp()) {
+    *error_msg = StringPrintf("Type cannot be marked as both %s and %s.",
+                              kUtf8Annotation, kUtf8InCppAnnotation);
+    return nullptr;
+  }
+
+  bool utf8 = aidl_type.IsUtf8();
+  bool utf8InCpp = aidl_type.IsUtf8InCpp();
+
+  // Strings inside containers get remapped to appropriate utf8 versions when
+  // we convert the container name to its canonical form and the look up the
+  // type.  However, for non-compound types (i.e. those not in a container) we
+  // must patch them up here.
+  if (IsContainerType(type->CanonicalName())) {
+    utf8 = false;
+    utf8InCpp = false;
+  } else if (aidl_type.GetName() == "String" ||
+             aidl_type.GetName() == "java.lang.String") {
+    utf8 = utf8 || interface.IsUtf8();
+    utf8InCpp = utf8InCpp || interface.IsUtf8InCpp();
+  } else if (utf8 || utf8InCpp) {
+    const char* annotation_literal =
+        (utf8) ? kUtf8Annotation : kUtf8InCppAnnotation;
+    *error_msg = StringPrintf("type '%s' may not be annotated as %s.",
+                              aidl_type.GetName().c_str(),
+                              annotation_literal);
+    return nullptr;
+  }
+
+  if (utf8) {
+    type = FindTypeByCanonicalName(kUtf8StringCanonicalName);
+  } else if (utf8InCpp) {
+    type = FindTypeByCanonicalName(kUtf8InCppStringCanonicalName);
+  }
+
+  // One of our UTF8 transforms made type null
+  if (type == nullptr) {
+    const char* annotation_literal =
+        (utf8) ? kUtf8Annotation : kUtf8InCppAnnotation;
+    *error_msg = StringPrintf(
+        "%s is unsupported when generating code for this language.",
+        annotation_literal);
+    return nullptr;
+  }
+
+  if (!type->CanWriteToParcel()) {
+    *error_msg = "type cannot be marshalled";
+    return nullptr;
+  }
+
+  if (aidl_type.IsArray()) {
+    type = type->ArrayType();
+    if (!type) {
+      *error_msg = StringPrintf("type '%s' cannot be an array",
+                                aidl_type.GetName().c_str());
+      return nullptr;
+    }
+  }
+
+  if (interface.IsNullable()) {
+    const ValidatableType* nullableType = type->NullableType();
+
+    if (nullableType) {
+      return nullableType;
+    }
+  }
+
+  if (aidl_type.IsNullable()) {
+    type = type->NullableType();
+    if (!type) {
+      *error_msg = StringPrintf("type '%s%s' cannot be marked as possibly null",
+                                aidl_type.GetName().c_str(),
+                                (aidl_type.IsArray()) ? "[]" : "");
+      return nullptr;
+    }
+  }
+
+  return type;
+}
+
+}  // namespace aidl
+}  // namespace android
+
+#endif  // AIDL_TYPE_NAMESPACE_H_