generate C++ interface header, proxy and stub headers and sources.
diff --git a/AST.h b/AST.h
index 497deb7..942b718 100644
--- a/AST.h
+++ b/AST.h
@@ -7,12 +7,14 @@
 #include <utils/Vector.h>
 
 #include "FQName.h"
+#include "Type.h"
 
 namespace android {
 
 struct Coordinator;
 struct Formatter;
-struct Type;
+struct Method;
+struct TypedVar;
 struct Scope;
 
 struct AST {
@@ -45,6 +47,8 @@
 
     void dump(Formatter &out) const;
 
+    status_t generateCpp() const;
+
 private:
     Coordinator *mCoordinator;
     Vector<Scope *> mScopePath;
@@ -54,6 +58,41 @@
 
     FQName mPackage;
 
+    void getPackageComponents(std::vector<std::string> *components) const;
+
+    void getPackageAndVersionComponents(
+            std::vector<std::string> *components, bool cpp_compatible) const;
+
+    std::string makeHeaderGuard(const std::string &baseName) const;
+    void enterLeaveNamespace(Formatter &out, bool enter) const;
+
+    status_t generateInterfaceHeader() const;
+    status_t generateStubHeader() const;
+    status_t generateProxyHeader() const;
+    status_t generateAllSource() const;
+
+    status_t generateTypeSource(
+            Formatter &out, const std::string &ifaceName) const;
+
+    status_t generateProxySource(
+            Formatter &out, const std::string &baseName) const;
+
+    status_t generateStubSource(
+            Formatter &out, const std::string &baseName) const;
+
+    status_t generateStubSourceForMethod(
+            Formatter &out, const Method *method) const;
+
+    void emitCppReaderWriter(
+            Formatter &out,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            const TypedVar *arg,
+            bool isReader,
+            Type::ErrorMode mode) const;
+
+    status_t emitTypeDeclarations(Formatter &out) const;
+
     DISALLOW_COPY_AND_ASSIGN(AST);
 };
 
diff --git a/Android.mk b/Android.mk
index ac3e3f4..4ae915f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -13,6 +13,7 @@
     EnumType.cpp                \
     Formatter.cpp               \
     FQName.cpp                  \
+    generateCpp.cpp             \
     HandleType.cpp              \
     hidl-gen_y.yy               \
     hidl-gen_l.ll               \
@@ -36,4 +37,6 @@
 LOCAL_STATIC_LIBRARIES :=       \
     libutils                    \
 
+LOCAL_CFLAGS := -O0 -g
+
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/ArrayType.cpp b/ArrayType.cpp
index 9137de1..7feb9fb 100644
--- a/ArrayType.cpp
+++ b/ArrayType.cpp
@@ -2,6 +2,8 @@
 
 #include "Formatter.h"
 
+#include <android-base/logging.h>
+
 namespace android {
 
 ArrayType::ArrayType(Type *elementType, const char *dimension)
@@ -14,5 +16,136 @@
     out << "[" << mDimension << "]";
 }
 
+std::string ArrayType::getCppType(StorageMode mode, std::string *extra) const {
+    const std::string base = mElementType->getCppType(extra);
+
+    CHECK(extra->empty());
+
+    *extra = "[" + mDimension + "]";
+
+    switch (mode) {
+        case StorageMode_Stack:
+            return base;
+
+        case StorageMode_Argument:
+            return "const " + base;
+
+        case StorageMode_Result:
+        {
+            extra->clear();
+            return "const " + base + "*";
+        }
+    }
+}
+
+void ArrayType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    std::string baseExtra;
+    std::string baseType = mElementType->getCppType(&baseExtra);
+
+    const std::string parentName = "_aidl_" + name + "_parent";
+
+    out << "size_t " << parentName << ";\n\n";
+
+    const std::string parcelObjDeref =
+        parcelObj + (parcelObjIsPointer ? "->" : ".");
+
+    if (isReader) {
+        out << name
+            << " = (const "
+            << baseType
+            << " *)"
+            << parcelObjDeref
+            << "readBuffer(&"
+            << parentName
+            << ");\n\n";
+
+        out << "if (" << name << " == nullptr) {\n";
+
+        out.indent();
+
+        out << "_aidl_err = ::android::UNKNOWN_ERROR;\n";
+        handleError2(out, mode);
+
+        out.unindent();
+        out << "}\n\n";
+    } else {
+        out << "_aidl_err = "
+            << parcelObjDeref
+            << "writeBuffer("
+            << name
+            << ", "
+            << mDimension
+            << " * sizeof("
+            << baseType
+            << "), &"
+            << parentName
+            << ");\n";
+
+        handleError(out, mode);
+    }
+
+    emitReaderWriterEmbedded(
+            out,
+            name,
+            isReader /* nameIsPointer */,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            "0 /* parentOffset */");
+}
+
+void ArrayType::emitReaderWriterEmbedded(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText) const {
+    if (!mElementType->needsEmbeddedReadWrite()) {
+        return;
+    }
+
+    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
+
+    std::string baseExtra;
+    std::string baseType = mElementType->getCppType(&baseExtra);
+
+    out << "for (size_t _aidl_index = 0; _aidl_index < "
+        << mDimension
+        << "; ++_aidl_index) {\n";
+
+    out.indent();
+
+    mElementType->emitReaderWriterEmbedded(
+            out,
+            name + "[_aidl_index]",
+            false /* nameIsPointer */,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            offsetText + " + _aidl_index * sizeof(" + baseType + ")");
+
+    out.unindent();
+
+    out << "}\n\n";
+}
+
+bool ArrayType::needsEmbeddedReadWrite() const {
+    return mElementType->needsEmbeddedReadWrite();
+}
+
 }  // namespace android
 
diff --git a/ArrayType.h b/ArrayType.h
index 25320f4..3e44fe4 100644
--- a/ArrayType.h
+++ b/ArrayType.h
@@ -13,6 +13,29 @@
 
     void dump(Formatter &out) const override;
 
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const override;
+
+    bool needsEmbeddedReadWrite() const override;
+
 private:
     Type *mElementType;
     std::string mDimension;
diff --git a/CompoundType.cpp b/CompoundType.cpp
index ce8dc86..a96c7e2 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -15,13 +15,21 @@
     out << " " << mName << ";";
 }
 
+std::string CompoundField::name() const {
+    return mName;
+}
+
+const Type &CompoundField::type() const {
+    return *mType;
+}
+
 CompoundType::CompoundType(Style style, const char *name)
     : Scope(name),
       mStyle(style),
       mFields(NULL) {
 }
 
-void CompoundType::setFields(Vector<CompoundField *> *fields) {
+void CompoundType::setFields(std::vector<CompoundField *> *fields) {
     mFields = fields;
 }
 
@@ -36,7 +44,7 @@
     Scope::dump(out);
 
     for (size_t i = 0; i < mFields->size(); ++i) {
-        mFields->itemAt(i)->dump(out);
+        (*mFields)[i]->dump(out);
         out << "\n";
     }
 
@@ -45,5 +53,258 @@
     out << "};\n\n";
 }
 
+std::string CompoundType::getCppType(
+        StorageMode mode, std::string *extra) const {
+    extra->clear();
+    const std::string base = name();
+
+    switch (mode) {
+        case StorageMode_Stack:
+            return base;
+
+        case StorageMode_Argument:
+            return "const " + base + "&";
+
+        case StorageMode_Result:
+            return "const " + base + "*";
+    }
+}
+
+void CompoundType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    const std::string parentName = "_aidl_" + name + "_parent";
+
+    out << "size_t " << parentName << ";\n\n";
+
+    const std::string parcelObjDeref =
+        parcelObj + (parcelObjIsPointer ? "->" : ".");
+
+    if (isReader) {
+        out << name
+            << " = (const "
+            << this->name()
+            << " *)"
+            << parcelObjDeref
+            << "readBuffer("
+            << "&"
+            << parentName
+            << ");\n";
+
+        out << "if ("
+            << name
+            << " == nullptr) {\n";
+
+        out.indent();
+
+        out << "_aidl_err = ::android::UNKNOWN_ERROR;\n";
+        handleError2(out, mode);
+
+        out.unindent();
+        out << "}\n\n";
+    } else {
+        out << "_aidl_err = "
+            << parcelObjDeref
+            << "writeBuffer(&"
+            << name
+            << ", sizeof("
+            << name
+            << "), &"
+            << parentName
+            << ");\n";
+
+        handleError(out, mode);
+    }
+
+    if (mStyle != STYLE_STRUCT || !needsEmbeddedReadWrite()) {
+        return;
+    }
+
+    emitReaderWriterEmbedded(
+            out,
+            name,
+            isReader /* nameIsPointer */,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            "0 /* parentOffset */");
+}
+
+void CompoundType::emitReaderWriterEmbedded(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText) const {
+    emitReaderWriterEmbeddedForTypeName(
+            out,
+            name,
+            nameIsPointer,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            offsetText,
+            this->name(),
+            "" /* childName */);
+}
+
+status_t CompoundType::emitTypeDeclarations(Formatter &out) const {
+    out << ((mStyle == STYLE_STRUCT) ? "struct" : "union")
+        << " "
+        << name()
+        << " {\n";
+
+    out.indent();
+
+    Scope::emitTypeDeclarations(out);
+
+    for (const auto &field : *mFields) {
+        std::string extra;
+        out << field->type().getCppType(&extra)
+            << " "
+            << field->name()
+            << extra
+            << ";\n";
+    }
+
+    if (needsEmbeddedReadWrite()) {
+        out << "\n::android::status_t readEmbeddedFromParcel(\n";
+
+        out.indent();
+        out.indent();
+
+        out << "const ::android::hidl::Parcel &parcel,\n"
+                  << "size_t parentHandle,\n"
+                  << "size_t parentOffset);\n\n";
+
+        out.unindent();
+        out.unindent();
+
+        out << "::android::status_t writeEmbeddedToParcel(\n";
+
+        out.indent();
+        out.indent();
+
+        out << "::android::hidl::Parcel *parcel,\n"
+                  << "size_t parentHandle,\n"
+                  << "size_t parentOffset) const;\n";
+
+        out.unindent();
+        out.unindent();
+    }
+
+    out.unindent();
+    out << "};\n\n";
+
+    return OK;
+}
+
+status_t CompoundType::emitTypeDefinitions(
+        Formatter &out, const std::string prefix) const {
+    status_t err = Scope::emitTypeDefinitions(out, prefix + "::" + name());
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (!needsEmbeddedReadWrite()) {
+        return OK;
+    }
+
+    emitStructReaderWriter(out, prefix, true /* isReader */);
+    emitStructReaderWriter(out, prefix, false /* isReader */);
+
+    return OK;
+}
+
+void CompoundType::emitStructReaderWriter(
+        Formatter &out, const std::string &prefix, bool isReader) const {
+    out << "::android::status_t "
+              << (prefix.empty() ? "" : (prefix + "::"))
+              << name()
+              << (isReader ? "::readEmbeddedFromParcel"
+                           : "::writeEmbeddedToParcel")
+              << "(\n";
+
+    out.indent();
+    out.indent();
+
+    if (isReader) {
+        out << "const ::android::hidl::Parcel &parcel,\n";
+    } else {
+        out << "::android::hidl::Parcel *parcel,\n";
+    }
+
+    out << "size_t parentHandle,\n"
+        << "size_t parentOffset)";
+
+    if (!isReader) {
+        out << " const";
+    }
+
+    out << " {\n";
+
+    out.unindent();
+    out.unindent();
+    out.indent();
+
+    out << "::android::status_t _aidl_err = ::android::OK;\n\n";
+
+    for (const auto &field : *mFields) {
+        if (!field->type().needsEmbeddedReadWrite()) {
+            continue;
+        }
+
+        field->type().emitReaderWriterEmbedded(
+                out,
+                field->name(),
+                false /* nameIsPointer */,
+                "parcel",
+                !isReader /* parcelObjIsPointer */,
+                isReader,
+                ErrorMode_Goto,
+                "parentHandle",
+                "parentOffset + offsetof(" + name() + ", " + field->name() + ")");
+    }
+
+    out.unindent();
+    out << "_aidl_error:\n";
+    out.indent();
+    out << "return _aidl_err;\n";
+
+    out.unindent();
+    out << "}\n\n";
+}
+
+bool CompoundType::needsEmbeddedReadWrite() const {
+    if (mStyle != STYLE_STRUCT) {
+        return false;
+    }
+
+    for (const auto &field : *mFields) {
+        if (field->type().needsEmbeddedReadWrite()) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool CompoundType::resultNeedsDeref() const {
+    return true;
+}
+
 }  // namespace android
 
diff --git a/CompoundType.h b/CompoundType.h
index 8d4b837..7653a1a 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -4,7 +4,7 @@
 
 #include "Scope.h"
 
-#include <utils/Vector.h>
+#include <vector>
 
 namespace android {
 
@@ -13,6 +13,9 @@
 
     void dump(Formatter &out) const;
 
+    std::string name() const;
+    const Type &type() const;
+
 private:
     std::string mName;
     Type *mType;
@@ -28,13 +31,45 @@
 
     CompoundType(Style style, const char *name);
 
-    void setFields(Vector<CompoundField *> *fields);
+    void setFields(std::vector<CompoundField *> *fields);
 
     void dump(Formatter &out) const override;
 
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const override;
+
+    status_t emitTypeDeclarations(Formatter &out) const override;
+
+    status_t emitTypeDefinitions(
+            Formatter &out, const std::string prefix) const override;
+
+    bool needsEmbeddedReadWrite() const override;
+    bool resultNeedsDeref() const override;
+
 private:
     Style mStyle;
-    Vector<CompoundField *> *mFields;
+    std::vector<CompoundField *> *mFields;
+
+    void emitStructReaderWriter(
+            Formatter &out, const std::string &prefix, bool isReader) const;
 
     DISALLOW_COPY_AND_ASSIGN(CompoundType);
 };
diff --git a/Coordinator.cpp b/Coordinator.cpp
index 196c739..97b176f 100644
--- a/Coordinator.cpp
+++ b/Coordinator.cpp
@@ -102,7 +102,8 @@
     return ast;
 }
 
-std::string Coordinator::getPackagePath(const FQName &fqName) const {
+std::string Coordinator::getPackagePath(
+        const FQName &fqName, bool relative) const {
     CHECK(!fqName.package().empty());
     CHECK(!fqName.version().empty());
     const char *const kPrefix = "android.hardware.";
@@ -110,7 +111,10 @@
 
     const std::string packageSuffix = fqName.package().substr(strlen(kPrefix));
 
-    std::string packagePath = mInterfacesPath;
+    std::string packagePath;
+    if (!relative) {
+        packagePath = mInterfacesPath;
+    }
 
     size_t startPos = 0;
     size_t dotPos;
diff --git a/Coordinator.h b/Coordinator.h
index 0594d5b..8f72e7e 100644
--- a/Coordinator.h
+++ b/Coordinator.h
@@ -20,7 +20,8 @@
 
     Type *lookupType(const FQName &fqName) const;
 
-    std::string getPackagePath(const FQName &fqName) const;
+    std::string getPackagePath(
+            const FQName &fqName, bool relative = false) const;
 
 private:
     std::string mInterfacesPath;
diff --git a/EnumType.cpp b/EnumType.cpp
index c4d27c1..506c796 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -1,6 +1,7 @@
 #include "EnumType.h"
 
 #include "Formatter.h"
+#include "ScalarType.h"
 
 namespace android {
 
@@ -19,11 +20,22 @@
     out << ",";
 }
 
+std::string EnumValue::name() const {
+    return mName;
+}
+
+const char *EnumValue::value() const {
+    return mValue;
+}
+
 EnumType::EnumType(
-        const char *name, Vector<EnumValue *> *values, Type *storageType)
+        const char *name, std::vector<EnumValue *> *values, Type *storageType)
     : NamedType(name),
       mValues(values),
-      mStorageType(storageType) {
+      mStorageType(
+              storageType != NULL
+                ? storageType
+                : new ScalarType(ScalarType::KIND_INT32)) {
 }
 
 void EnumType::dump(Formatter &out) const {
@@ -39,7 +51,7 @@
     out.indent();
 
     for (size_t i = 0; i < mValues->size(); ++i) {
-        mValues->itemAt(i)->dump(out);
+        (*mValues)[i]->dump(out);
         out << "\n";
     }
 
@@ -48,5 +60,50 @@
     out << "};\n\n";
 }
 
+std::string EnumType::getCppType(StorageMode, std::string *extra) const {
+    extra->clear();
+
+    return name();
+}
+
+void EnumType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    mStorageType->emitReaderWriter(
+            out, name, parcelObj, parcelObjIsPointer, isReader, mode);
+}
+
+status_t EnumType::emitTypeDeclarations(Formatter &out) const {
+    std::string extra;
+
+    out << "enum class "
+        << name()
+        << " : "
+        << mStorageType->getCppType(&extra)
+        << " {\n";
+
+    out.indent();
+
+    for (const auto &entry : *mValues) {
+        out << entry->name();
+
+        const char *value = entry->value();
+        if (value != NULL) {
+            out << " = " << value;
+        }
+
+        out << ",\n";
+    }
+
+    out.unindent();
+    out << "};\n\n";
+
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/EnumType.h b/EnumType.h
index 7f44d59..a0d866a 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -4,7 +4,7 @@
 
 #include "NamedType.h"
 
-#include <utils/Vector.h>
+#include <vector>
 
 namespace android {
 
@@ -13,6 +13,9 @@
 
     void dump(Formatter &out) const;
 
+    std::string name() const;
+    const char *value() const;
+
 private:
     std::string mName;
     const char *mValue;
@@ -22,13 +25,25 @@
 
 struct EnumType : public NamedType {
     EnumType(const char *name,
-             Vector<EnumValue *> *values,
+             std::vector<EnumValue *> *values,
              Type *storageType = NULL);
 
     void dump(Formatter &out) const override;
 
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    status_t emitTypeDeclarations(Formatter &out) const override;
+
 private:
-    Vector<EnumValue *> *mValues;
+    std::vector<EnumValue *> *mValues;
     Type *mStorageType;
 
     DISALLOW_COPY_AND_ASSIGN(EnumType);
diff --git a/Formatter.cpp b/Formatter.cpp
index 50b5368..bd04271 100644
--- a/Formatter.cpp
+++ b/Formatter.cpp
@@ -6,11 +6,19 @@
 
 namespace android {
 
-Formatter::Formatter()
-    : mIndentDepth(0),
+Formatter::Formatter(FILE *file)
+    : mFile(file == NULL ? stdout : file),
+      mIndentDepth(0),
       mAtStartOfLine(true) {
 }
 
+Formatter::~Formatter() {
+    if (mFile != stdout) {
+        fclose(mFile);
+    }
+    mFile = NULL;
+}
+
 void Formatter::indent() {
     ++mIndentDepth;
 }
@@ -28,23 +36,23 @@
 
         if (pos == string::npos) {
             if (mAtStartOfLine) {
-                printf("%*s", (int)(2 * mIndentDepth), "");
+                fprintf(mFile, "%*s", (int)(2 * mIndentDepth), "");
                 mAtStartOfLine = false;
             }
 
-            printf("%s", out.substr(start).c_str());
+            fprintf(mFile, "%s", out.substr(start).c_str());
             break;
         }
 
         if (pos == start) {
-            printf("\n");
+            fprintf(mFile, "\n");
             mAtStartOfLine = true;
         } else if (pos > start) {
             if (mAtStartOfLine) {
-                printf("%*s", (int)(2 * mIndentDepth), "");
+                fprintf(mFile, "%*s", (int)(2 * mIndentDepth), "");
             }
 
-            printf("%s", out.substr(start, pos - start + 1).c_str());
+            fprintf(mFile, "%s", out.substr(start, pos - start + 1).c_str());
 
             mAtStartOfLine = true;
         }
diff --git a/Formatter.h b/Formatter.h
index 38e5419..a768608 100644
--- a/Formatter.h
+++ b/Formatter.h
@@ -24,7 +24,9 @@
 namespace android {
 
 struct Formatter {
-    Formatter();
+    // Assumes ownership of file. Directed to stdout if file == NULL.
+    Formatter(FILE *file = NULL);
+    ~Formatter();
 
     void indent();
     void unindent();
@@ -33,6 +35,7 @@
     Formatter &operator<<(size_t n);
 
 private:
+    FILE *mFile;
     size_t mIndentDepth;
     bool mAtStartOfLine;
 
diff --git a/HandleType.cpp b/HandleType.cpp
index 70ffa5f..ea5d665 100644
--- a/HandleType.cpp
+++ b/HandleType.cpp
@@ -10,5 +10,136 @@
     out << "handle";
 }
 
+std::string HandleType::getCppType(StorageMode mode, std::string *extra) const {
+    extra->clear();
+
+    const std::string base = "::android::sp<::android::NativeHandle>";
+
+    switch (mode) {
+        case StorageMode_Stack:
+        case StorageMode_Result:
+            return base;
+
+        case StorageMode_Argument:
+            return "const " + base + "&";
+    }
+}
+
+void HandleType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    const std::string parcelObjDeref =
+        parcelObj + (parcelObjIsPointer ? "->" : ".");
+
+    if (isReader) {
+        out << name
+            << " = "
+            << "::android::NativeHandle::create(\n";
+
+        out.indent();
+        out.indent();
+
+        out << parcelObjDeref
+            << "readNativeHandle(), true /* ownsHandle */);\n\n";
+
+        out.unindent();
+        out.unindent();
+
+        out << "if ("
+            << name
+            << " == nullptr) {\n";
+
+        out.indent();
+
+        out << "_aidl_err = ::android::UNKNOWN_ERROR;\n";
+        handleError2(out, mode);
+
+        out.unindent();
+        out << "}\n\n";
+    } else {
+        out << "_aidl_err = ";
+        out << parcelObjDeref
+            << "writeNativeHandle("
+            << name
+            << "->handle());\n";
+
+        handleError(out, mode);
+    }
+}
+
+void HandleType::emitReaderWriterEmbedded(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText) const {
+    if (isReader) {
+        const std::string ptrName = "_aidl_" + name  + "_ptr";
+
+        out << "const native_handle_t *"
+            << ptrName
+            << " = "
+            << parcelObj
+            << (parcelObjIsPointer ? "->" : ".")
+            << "readEmbeddedNativeHandle(\n";
+
+        out.indent();
+        out.indent();
+
+        out << parentName
+            << ",\n"
+            << offsetText
+            << "/* + offsetof(::android::NativeHandle, mHandle) */"
+            << ");\n\n";
+
+        out.unindent();
+        out.unindent();
+
+        out << "if ("
+            << ptrName
+            << " == nullptr) {\n";
+
+        out.indent();
+        out << "_aidl_err = ::android::UNKNOWN_ERROR;\n";
+        handleError2(out, mode);
+        out.unindent();
+        out << "}\n\n";
+    } else {
+        out << "_aidl_err = "
+            << parcelObj
+            << (parcelObjIsPointer ? "->" : ".")
+            << "writeEmbeddedNativeHandle(\n";
+
+        out.indent();
+        out.indent();
+
+        out << name
+            << (nameIsPointer ? "->" : ".")
+            << "handle(),\n"
+            << parentName
+            << ",\n"
+            << offsetText
+            << "/* + offsetof(::android::NativeHandle, mHandle) */"
+            << ");\n\n";
+
+        out.unindent();
+        out.unindent();
+
+        handleError(out, mode);
+    }
+}
+
+bool HandleType::needsEmbeddedReadWrite() const {
+    return true;
+}
+
 }  // namespace android
 
diff --git a/HandleType.h b/HandleType.h
index fa9eb8e..5eb283d 100644
--- a/HandleType.h
+++ b/HandleType.h
@@ -10,6 +10,29 @@
     HandleType();
 
     void dump(Formatter &out) const override;
+
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const override;
+
+    bool needsEmbeddedReadWrite() const override;
 };
 
 }  // namespace android
diff --git a/Interface.cpp b/Interface.cpp
index ef4b573..f845bc5 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -46,5 +46,66 @@
     return true;
 }
 
+const std::vector<Method *> &Interface::methods() const {
+    return mMethods;
+}
+
+std::string Interface::getCppType(StorageMode mode, std::string *extra) const {
+    extra->clear();
+    const std::string base = "::android::sp<" + name() + ">";
+
+    switch (mode) {
+        case StorageMode_Stack:
+        case StorageMode_Result:
+            return base;
+
+        case StorageMode_Argument:
+            return "const " + base + "&";
+    }
+}
+
+void Interface::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    const std::string parcelObjDeref =
+        parcelObj + (parcelObjIsPointer ? "->" : ".");
+
+    if (isReader) {
+        const std::string binderName = "_aidl_" + name + "_binder";
+
+        out << "::android::sp<::android::hidl::IBinder> "
+            << binderName << ";\n";
+
+        out << "_aidl_err = ";
+        out << parcelObjDeref
+            << "readNullableStrongBinder(&"
+            << binderName
+            << ");\n";
+
+        handleError(out, mode);
+
+        out << name
+            << " = "
+            << this->name()
+            << "::asInterface("
+            << binderName
+            << ");\n";
+    } else {
+        out << "_aidl_err = ";
+        out << parcelObjDeref
+            << "writeStrongBinder("
+            << this->name()
+            << "::asBinder("
+            << name
+            << "));\n";
+
+        handleError(out, mode);
+    }
+}
+
 }  // namespace android
 
diff --git a/Interface.h b/Interface.h
index 1a035b6..04a272c 100644
--- a/Interface.h
+++ b/Interface.h
@@ -4,7 +4,7 @@
 
 #include "Scope.h"
 
-#include <utils/Vector.h>
+#include <vector>
 
 namespace android {
 
@@ -20,9 +20,21 @@
 
     const Type *superType() const;
 
+    const std::vector<Method *> &methods() const;
+
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
 private:
     Type *mSuperType;
-    Vector<Method *> mMethods;
+    std::vector<Method *> mMethods;
 
     DISALLOW_COPY_AND_ASSIGN(Interface);
 };
diff --git a/Method.cpp b/Method.cpp
index b9eb885..b6281d1 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -16,10 +16,19 @@
     out << mName;
 }
 
+std::string TypedVar::name() const {
+    return mName;
+}
+
+const Type &TypedVar::type() const {
+    return *mType;
+}
+
+
 Method::Method(
         const char *name,
-        Vector<TypedVar *> *args,
-        Vector<TypedVar *> *results)
+        std::vector<TypedVar *> *args,
+        std::vector<TypedVar *> *results)
     : mName(name),
       mArgs(args),
       mResults(results) {
@@ -33,7 +42,7 @@
             out << ", ";
         }
 
-        mArgs->itemAt(i)->dump(out);
+        (*mArgs)[i]->dump(out);
     }
 
     out << ")";
@@ -46,7 +55,7 @@
                 out << ", ";
             }
 
-            mResults->itemAt(i)->dump(out);
+            (*mResults)[i]->dump(out);
         }
 
         out << ")";
@@ -55,5 +64,38 @@
     out << ";";
 }
 
+std::string Method::name() const {
+    return mName;
+}
+
+const std::vector<TypedVar *> &Method::args() const {
+    return *mArgs;
+}
+
+const std::vector<TypedVar *> &Method::results() const {
+    return *mResults;
+}
+
+// static
+std::string Method::GetSignature(const std::vector<TypedVar *> &args) {
+    bool first = true;
+    std::string out;
+    for (const auto &arg : args) {
+        if (!first) {
+            out += ", ";
+        }
+
+        std::string extra;
+        out += arg->type().getCppArgumentType(&extra);
+        out += " ";
+        out += arg->name();
+        out += extra;
+
+        first = false;
+    }
+
+    return out;
+}
+
 }  // namespace android
 
diff --git a/Method.h b/Method.h
index 3f80402..ab5cefc 100644
--- a/Method.h
+++ b/Method.h
@@ -4,7 +4,7 @@
 
 #include <android-base/macros.h>
 #include <string>
-#include <utils/Vector.h>
+#include <vector>
 
 namespace android {
 
@@ -16,6 +16,9 @@
 
     void dump(Formatter &out) const;
 
+    std::string name() const;
+    const Type &type() const;
+
 private:
     std::string mName;
     Type *mType;
@@ -25,15 +28,21 @@
 
 struct Method {
     Method(const char *name,
-           Vector<TypedVar *> *args,
-           Vector<TypedVar *> *results = NULL);
+           std::vector<TypedVar *> *args,
+           std::vector<TypedVar *> *results = NULL);
 
     void dump(Formatter &out) const;
 
+    std::string name() const;
+    const std::vector<TypedVar *> &args() const;
+    const std::vector<TypedVar *> &results() const;
+
+    static std::string GetSignature(const std::vector<TypedVar *> &args);
+
 private:
     std::string mName;
-    Vector<TypedVar *> *mArgs;
-    Vector<TypedVar *> *mResults;
+    std::vector<TypedVar *> *mArgs;
+    std::vector<TypedVar *> *mResults;
 
     DISALLOW_COPY_AND_ASSIGN(Method);
 };
diff --git a/RefType.cpp b/RefType.cpp
index fe1fb51..c71d1d7 100644
--- a/RefType.cpp
+++ b/RefType.cpp
@@ -17,5 +17,42 @@
     out << name();
 }
 
+std::string RefType::getCppType(StorageMode mode, std::string *extra) const {
+    return mReferencedType->getCppType(mode, extra);
+}
+
+void RefType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    mReferencedType->emitReaderWriter(
+            out, name, parcelObj, parcelObjIsPointer, isReader, mode);
+}
+
+void RefType::emitReaderWriterEmbedded(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText) const {
+    mReferencedType->emitReaderWriterEmbedded(
+            out,
+            name,
+            nameIsPointer,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            offsetText);
+}
+
 }  // namespace android
 
diff --git a/RefType.h b/RefType.h
index 74093fc..87e2194 100644
--- a/RefType.h
+++ b/RefType.h
@@ -13,6 +13,27 @@
 
     const Type *referencedType() const;
 
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const override;
+
 private:
     Type *mReferencedType;
 
diff --git a/ScalarType.cpp b/ScalarType.cpp
index ef816a9..c498f8c 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -16,5 +16,69 @@
     out << kName[mKind];
 }
 
+std::string ScalarType::getCppType(StorageMode, std::string *extra) const {
+    static const char *const kName[] = {
+        "char",
+        "bool",
+        "void *",
+        "int8_t",
+        "uint8_t",
+        "int16_t",
+        "uint16_t",
+        "int32_t",
+        "uint32_t",
+        "int64_t",
+        "uint64_t",
+        "float",
+        "double"
+    };
+
+    extra->clear();
+
+    return kName[mKind];
+}
+
+void ScalarType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    static const char *const kSuffix[] = {
+        "Uint8",
+        "Uint8",
+        "Pointer",
+        "Int8",
+        "Uint8",
+        "Int16",
+        "Uint16",
+        "Int32",
+        "Uint32",
+        "Int64",
+        "Uint64",
+        "Float",
+        "Double"
+    };
+
+    const std::string parcelObjDeref =
+        parcelObj + (parcelObjIsPointer ? "->" : ".");
+
+    out << "_aidl_err = "
+        << parcelObjDeref
+        << (isReader ? "read" : "write")
+        << kSuffix[mKind]
+        << "(";
+
+    if (isReader) {
+        out << "&";
+    }
+
+    out << name
+        << ");\n";
+
+    handleError(out, mode);
+}
+
 }  // namespace android
 
diff --git a/ScalarType.h b/ScalarType.h
index e574b80..2bd7cae 100644
--- a/ScalarType.h
+++ b/ScalarType.h
@@ -27,6 +27,16 @@
 
     void dump(Formatter &out) const override;
 
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
 private:
     Kind mKind;
 
diff --git a/Scope.cpp b/Scope.cpp
index 45d766e..a009204 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -64,14 +64,49 @@
     return true;
 }
 
-bool Scope::containsSingleInterface(std::string *ifaceName) const {
+Interface *Scope::getInterface() const {
     if (mTypes.size() == 1 && mTypes[0]->isInterface()) {
-        *ifaceName = static_cast<Interface *>(mTypes[0])->name();
+        return static_cast<Interface *>(mTypes[0]);
+    }
+
+    return NULL;
+}
+
+bool Scope::containsSingleInterface(std::string *ifaceName) const {
+    Interface *iface = getInterface();
+
+    if (iface != NULL) {
+        *ifaceName = iface->name();
         return true;
     }
 
     return false;
 }
 
+status_t Scope::emitTypeDeclarations(Formatter &out) const {
+    for (size_t i = 0; i < mTypes.size(); ++i) {
+        status_t err = mTypes[i]->emitTypeDeclarations(out);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+status_t Scope::emitTypeDefinitions(
+        Formatter &out, const std::string prefix) const {
+    for (size_t i = 0; i < mTypes.size(); ++i) {
+        status_t err = mTypes[i]->emitTypeDefinitions(out, prefix);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/Scope.h b/Scope.h
index b5c65d6..132e20c 100644
--- a/Scope.h
+++ b/Scope.h
@@ -10,6 +10,8 @@
 namespace android {
 
 struct Constant;
+struct Formatter;
+struct Interface;
 
 struct Scope : public NamedType {
     Scope(const char *name);
@@ -21,8 +23,17 @@
 
     void dump(Formatter &out) const override;
     bool isScope() const override;
+
+    // Returns the single interface or NULL.
+    Interface *getInterface() const;
+
     bool containsSingleInterface(std::string *ifaceName) const;
 
+    status_t emitTypeDeclarations(Formatter &out) const override;
+
+    status_t emitTypeDefinitions(
+            Formatter &out, const std::string prefix) const override;
+
 private:
     Vector<Type *> mTypes;
     KeyedVector<std::string, size_t> mTypeIndexByName;
diff --git a/StringType.cpp b/StringType.cpp
index 2356e3a..52b27fe 100644
--- a/StringType.cpp
+++ b/StringType.cpp
@@ -10,5 +10,113 @@
     out << "string";
 }
 
+std::string StringType::getCppType(StorageMode mode, std::string *extra) const {
+    extra->clear();
+
+    const std::string base = "::android::hidl::hidl_string";
+
+    switch (mode) {
+        case StorageMode_Stack:
+            return base;
+
+        case StorageMode_Argument:
+            return "const " + base + "&";
+
+        case StorageMode_Result:
+            return "const " + base + "*";
+    }
+}
+
+void StringType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    const std::string parentName = "_aidl_" + name + "_parent";
+    out << "size_t " << parentName << ";\n\n";
+
+    const std::string parcelObjDeref =
+        parcelObj + (parcelObjIsPointer ? "->" : ".");
+
+    if (isReader) {
+        out << name
+            << " = (const ::android::hidl::hidl_string *)"
+            << parcelObjDeref
+            << "readBuffer("
+            << "&"
+            << parentName
+            << ");\n";
+
+        out << "if ("
+            << name
+            << " == nullptr) {\n";
+
+        out.indent();
+
+        out << "_aidl_err = ::android::UNKNOWN_ERROR;\n";
+        handleError2(out, mode);
+
+        out.unindent();
+        out << "}\n\n";
+    } else {
+        out << "_aidl_err = "
+            << parcelObjDeref
+            << "writeBuffer(&"
+            << name
+            << ", sizeof("
+            << name
+            << "), &"
+            << parentName
+            << ");\n";
+
+        handleError(out, mode);
+    }
+
+    emitReaderWriterEmbedded(
+            out,
+            name,
+            isReader /* nameIsPointer */,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            "0 /* parentOffset */");
+}
+
+void StringType::emitReaderWriterEmbedded(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText) const {
+    emitReaderWriterEmbeddedForTypeName(
+            out,
+            name,
+            nameIsPointer,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            offsetText,
+            "::android::hidl::hidl_string",
+            "" /* childName */);
+}
+
+bool StringType::needsEmbeddedReadWrite() const {
+    return true;
+}
+
+bool StringType::resultNeedsDeref() const {
+    return true;
+}
+
 }  // namespace android
 
diff --git a/StringType.h b/StringType.h
index 8016f4e..b50a9d8 100644
--- a/StringType.h
+++ b/StringType.h
@@ -10,6 +10,30 @@
     StringType();
 
     void dump(Formatter &out) const override;
+
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const override;
+
+    bool needsEmbeddedReadWrite() const override;
+    bool resultNeedsDeref() const override;
 };
 
 }  // namespace android
diff --git a/Type.cpp b/Type.cpp
index 136cb88..5f3c462 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -1,5 +1,9 @@
 #include "Type.h"
 
+#include "Formatter.h"
+
+#include <android-base/logging.h>
+
 namespace android {
 
 Type::Type() {}
@@ -13,5 +17,160 @@
     return false;
 }
 
+std::string Type::getCppType(StorageMode, std::string *) const {
+    CHECK(!"Should not be here");
+    return std::string();
+}
+
+void Type::emitReaderWriter(
+        Formatter &,
+        const std::string &,
+        const std::string &,
+        bool,
+        bool,
+        ErrorMode) const {
+    CHECK(!"Should not be here");
+}
+
+void Type::emitReaderWriterEmbedded(
+        Formatter &,
+        const std::string &,
+        bool,
+        const std::string &,
+        bool,
+        bool,
+        ErrorMode,
+        const std::string &,
+        const std::string &) const {
+    CHECK(!"Should not be here");
+}
+
+void Type::handleError(Formatter &out, ErrorMode mode) const {
+    switch (mode) {
+        case ErrorMode_Ignore:
+        {
+            out << "/* _aidl_err ignored! */\n\n";
+            break;
+        }
+
+        case ErrorMode_Goto:
+        {
+            out << "if (_aidl_err != ::android::OK) { goto _aidl_error; }\n\n";
+            break;
+        }
+
+        case ErrorMode_Break:
+        {
+            out << "if (_aidl_err != ::android::OK) { break; }\n\n";
+            break;
+        }
+    }
+}
+
+void Type::handleError2(Formatter &out, ErrorMode mode) const {
+    switch (mode) {
+        case ErrorMode_Goto:
+        {
+            out << "goto _aidl_error;\n";
+            break;
+        }
+        case ErrorMode_Break:
+        {
+            out << "break;\n";
+            break;
+        }
+        case ErrorMode_Ignore:
+        {
+            out << "/* ignoring _aidl_error! */";
+            break;
+        }
+    }
+}
+
+void Type::emitReaderWriterEmbeddedForTypeName(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText,
+        const std::string &typeName,
+        const std::string &childName) const {
+    const std::string parcelObjDeref =
+        parcelObjIsPointer ? ("*" + parcelObj) : parcelObj;
+
+    const std::string parcelObjPointer =
+        parcelObjIsPointer ? parcelObj : ("&" + parcelObj);
+
+    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
+    const std::string namePointer = nameIsPointer ? name : ("&" + name);
+
+    out << "_aidl_err = ";
+
+    if (isReader) {
+        out << "const_cast<"
+            << typeName
+            << " *>("
+            << namePointer
+            << ")->readEmbeddedFromParcel(\n";
+    } else {
+        out << nameDeref
+            << "writeEmbeddedToParcel(\n";
+    }
+
+    out.indent();
+    out.indent();
+
+    out << (isReader ? parcelObjDeref : parcelObjPointer)
+        << ",\n"
+        << parentName
+        << ",\n"
+        << offsetText;
+
+    if (!childName.empty()) {
+        out << ", &"
+            << childName;
+    }
+
+    out << ");\n\n";
+
+    out.unindent();
+    out.unindent();
+
+    handleError(out, mode);
+}
+
+status_t Type::emitTypeDeclarations(Formatter &) const {
+    return OK;
+}
+
+status_t Type::emitTypeDefinitions(
+        Formatter &, const std::string) const {
+    return OK;
+}
+
+bool Type::needsEmbeddedReadWrite() const {
+    return false;
+}
+
+bool Type::resultNeedsDeref() const {
+    return false;
+}
+
+std::string Type::getCppType(std::string *extra) const {
+    return getCppType(StorageMode_Stack, extra);
+}
+
+std::string Type::getCppResultType(std::string *extra) const {
+    return getCppType(StorageMode_Result, extra);
+}
+
+std::string Type::getCppArgumentType(std::string *extra) const {
+    return getCppType(StorageMode_Argument, extra);
+}
+
 }  // namespace android
 
diff --git a/Type.h b/Type.h
index e4d6d03..f7f8509 100644
--- a/Type.h
+++ b/Type.h
@@ -3,6 +3,8 @@
 #define TYPE_H_
 
 #include <android-base/macros.h>
+#include <string>
+#include <utils/Errors.h>
 
 namespace android {
 
@@ -16,6 +18,69 @@
     virtual bool isScope() const;
     virtual bool isInterface() const;
 
+    enum StorageMode {
+        StorageMode_Stack,
+        StorageMode_Argument,
+        StorageMode_Result
+    };
+    virtual std::string getCppType(
+            StorageMode mode, std::string *extra) const;
+
+    // Convenience, gets StorageMode_Stack type.
+    std::string getCppType(std::string *extra) const;
+
+    std::string getCppResultType(std::string *extra) const;
+    std::string getCppArgumentType(std::string *extra) const;
+
+    enum ErrorMode {
+        ErrorMode_Ignore,
+        ErrorMode_Goto,
+        ErrorMode_Break,
+    };
+    virtual void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const;
+
+    virtual void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const;
+
+    virtual status_t emitTypeDeclarations(Formatter &out) const;
+
+    virtual status_t emitTypeDefinitions(
+            Formatter &out, const std::string prefix) const;
+
+    virtual bool needsEmbeddedReadWrite() const;
+    virtual bool resultNeedsDeref() const;
+
+protected:
+    void handleError(Formatter &out, ErrorMode mode) const;
+    void handleError2(Formatter &out, ErrorMode mode) const;
+
+    void emitReaderWriterEmbeddedForTypeName(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText,
+            const std::string &typeName,
+            const std::string &childName) const;
+
 private:
     DISALLOW_COPY_AND_ASSIGN(Type);
 };
diff --git a/TypeDef.cpp b/TypeDef.cpp
index c365e5d..163a7e7 100644
--- a/TypeDef.cpp
+++ b/TypeDef.cpp
@@ -19,5 +19,42 @@
     out << " " << name() << ";\n\n";
 }
 
+std::string TypeDef::getCppType(StorageMode mode, std::string *extra) const {
+    return mReferencedType->getCppType(mode, extra);
+}
+
+void TypeDef::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    mReferencedType->emitReaderWriter(
+            out, name, parcelObj, parcelObjIsPointer, isReader, mode);
+}
+
+void TypeDef::emitReaderWriterEmbedded(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText) const {
+    mReferencedType->emitReaderWriterEmbedded(
+            out,
+            name,
+            nameIsPointer,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            offsetText);
+}
+
 }  // namespace android
 
diff --git a/TypeDef.h b/TypeDef.h
index 716c853..6e2c54c 100644
--- a/TypeDef.h
+++ b/TypeDef.h
@@ -13,6 +13,27 @@
 
     const Type *referencedType() const;
 
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const override;
+
 private:
     Type *mReferencedType;
 
diff --git a/VectorType.cpp b/VectorType.cpp
index 2343868..903478a 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -2,6 +2,8 @@
 
 #include "Formatter.h"
 
+#include <android-base/logging.h>
+
 namespace android {
 
 VectorType::VectorType(Type *elementType)
@@ -14,5 +16,154 @@
     out << ">";
 }
 
+std::string VectorType::getCppType(StorageMode mode, std::string *extra) const {
+    const std::string base =
+        "::android::hidl::hidl_vec<"
+        + mElementType->getCppType(extra)
+        + ">";
+
+    CHECK(extra->empty());
+
+    switch (mode) {
+        case StorageMode_Stack:
+            return base;
+
+        case StorageMode_Argument:
+            return "const " + base + "&";
+
+        case StorageMode_Result:
+            return "const " + base + "*";
+    }
+}
+
+void VectorType::emitReaderWriter(
+        Formatter &out,
+        const std::string &name,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode) const {
+    std::string baseExtra;
+    std::string baseType = mElementType->getCppType(&baseExtra);
+
+    const std::string parentName = "_aidl_" + name + "_parent";
+
+    out << "size_t " << parentName << ";\n\n";
+
+    const std::string parcelObjDeref =
+        parcelObj + (parcelObjIsPointer ? "->" : ".");
+
+    if (isReader) {
+        out << name
+            << " = (const ::android::hidl::hidl_vec<"
+            << baseType
+            << "> *)"
+            << parcelObjDeref
+            << "readBuffer(&"
+            << parentName
+            << ");\n\n";
+
+        out << "if (" << name << " == nullptr) {\n";
+
+        out.indent();
+
+        out << "_aidl_err = ::android::UNKNOWN_ERROR;\n";
+        handleError2(out, mode);
+
+        out.unindent();
+        out << "}\n\n";
+    } else {
+        out << "_aidl_err = "
+            << parcelObjDeref
+            << "writeBuffer(&"
+            << name
+            << ", sizeof("
+            << name
+            << "), &"
+            << parentName
+            << ");\n";
+
+        handleError(out, mode);
+    }
+
+    emitReaderWriterEmbedded(
+            out,
+            name,
+            isReader /* nameIsPointer */,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            "0 /* parentOffset */");
+}
+
+void VectorType::emitReaderWriterEmbedded(
+        Formatter &out,
+        const std::string &name,
+        bool nameIsPointer,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        bool isReader,
+        ErrorMode mode,
+        const std::string &parentName,
+        const std::string &offsetText) const {
+    std::string baseExtra;
+    std::string baseType = Type::getCppType(&baseExtra);
+
+    const std::string childName = "_aidl_" + name + "_child";
+    out << "size_t " << childName << ";\n\n";
+
+    emitReaderWriterEmbeddedForTypeName(
+            out,
+            name,
+            nameIsPointer,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            parentName,
+            offsetText,
+            baseType,
+            childName);
+
+    if (!mElementType->needsEmbeddedReadWrite()) {
+        return;
+    }
+
+    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
+
+    baseType = mElementType->getCppType(&baseExtra);
+
+    out << "for (size_t _aidl_index = 0; _aidl_index < "
+        << nameDeref
+        << "count; ++_aidl_index) {\n";
+
+    out.indent();
+
+    mElementType->emitReaderWriterEmbedded(
+            out,
+            nameDeref + "buffer[_aidl_index]",
+            false /* nameIsPointer */,
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode,
+            childName,
+            "_aidl_index * sizeof(" + baseType + ")");
+
+    out.unindent();
+
+    out << "}\n\n";
+}
+
+bool VectorType::needsEmbeddedReadWrite() const {
+    return true;
+}
+
+bool VectorType::resultNeedsDeref() const {
+    return true;
+}
+
 }  // namespace android
 
diff --git a/VectorType.h b/VectorType.h
index 0cde849..53092af 100644
--- a/VectorType.h
+++ b/VectorType.h
@@ -11,6 +11,30 @@
 
     void dump(Formatter &out) const override;
 
+    std::string getCppType(StorageMode mode, std::string *extra) const override;
+
+    void emitReaderWriter(
+            Formatter &out,
+            const std::string &name,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode) const override;
+
+    void emitReaderWriterEmbedded(
+            Formatter &out,
+            const std::string &name,
+            bool nameIsPointer,
+            const std::string &parcelObj,
+            bool parcelObjIsPointer,
+            bool isReader,
+            ErrorMode mode,
+            const std::string &parentName,
+            const std::string &offsetText) const override;
+
+    bool needsEmbeddedReadWrite() const override;
+    bool resultNeedsDeref() const override;
+
 private:
     Type *mElementType;
 
diff --git a/generateCpp.cpp b/generateCpp.cpp
new file mode 100644
index 0000000..f9b1189
--- /dev/null
+++ b/generateCpp.cpp
@@ -0,0 +1,889 @@
+#include "AST.h"
+
+#include "Coordinator.h"
+#include "Formatter.h"
+#include "Interface.h"
+#include "Method.h"
+#include "Scope.h"
+
+#include <android-base/logging.h>
+#include <sys/stat.h>
+#include <vector>
+
+namespace android {
+
+static bool MakeParentHierarchy(const std::string &path) {
+    static const mode_t kMode = 0755;
+
+    size_t start = 1;  // Ignore leading '/'
+    size_t slashPos;
+    while ((slashPos = path.find("/", start)) != std::string::npos) {
+        std::string partial = path.substr(0, slashPos);
+
+        struct stat st;
+        if (stat(partial.c_str(), &st) < 0) {
+            if (errno != ENOENT) {
+                return false;
+            }
+
+            int res = mkdir(partial.c_str(), kMode);
+            if (res < 0) {
+                return false;
+            }
+        } else if (!S_ISDIR(st.st_mode)) {
+            return false;
+        }
+
+        start = slashPos + 1;
+    }
+
+    return true;
+}
+
+static void SplitString(
+        const std::string &s, char c, std::vector<std::string> *components) {
+    components->clear();
+
+    size_t startPos = 0;
+    size_t matchPos;
+    while ((matchPos = s.find(c, startPos)) != std::string::npos) {
+        components->push_back(s.substr(startPos, matchPos - startPos));
+        startPos = matchPos + 1;
+    }
+
+    if (startPos + 1 < s.length()) {
+        components->push_back(s.substr(startPos));
+    }
+}
+
+static std::string upcase(const std::string in) {
+    std::string out{in};
+
+    for (auto &ch : out) {
+        ch = toupper(ch);
+    }
+
+    return out;
+}
+
+status_t AST::generateCpp() const {
+    status_t err = generateInterfaceHeader();
+
+    if (err == OK) {
+        err = generateStubHeader();
+    }
+
+    if (err == OK) {
+        err = generateProxyHeader();
+    }
+
+    if (err == OK) {
+        err = generateAllSource();
+    }
+
+    return err;
+}
+
+void AST::getPackageComponents(
+        std::vector<std::string> *components) const {
+    SplitString(mPackage.package(), '.', components);
+}
+
+void AST::getPackageAndVersionComponents(
+        std::vector<std::string> *components, bool cpp_compatible) const {
+    getPackageComponents(components);
+
+    const std::string packageVersion = mPackage.version();
+    CHECK(packageVersion[0] == '@');
+
+    if (!cpp_compatible) {
+        components->push_back(packageVersion.substr(1));
+        return;
+    }
+
+    const size_t dotPos = packageVersion.find('.');
+
+    // Form "Vmajor_minor".
+    std::string versionString = "V";
+    versionString.append(packageVersion.substr(1, dotPos - 1));
+    versionString.append("_");
+    versionString.append(packageVersion.substr(dotPos + 1));
+
+    components->push_back(versionString);
+}
+
+std::string AST::makeHeaderGuard(const std::string &baseName) const {
+    std::vector<std::string> packageComponents;
+    getPackageAndVersionComponents(
+            &packageComponents, true /* cpp_compatible */);
+
+    std::string guard = "HIDL_GENERATED";
+    for (const auto &component : packageComponents) {
+        guard += "_";
+        guard += component;
+    }
+
+    guard += "_";
+    guard += baseName;
+    guard += "_H_";
+
+    return guard;
+}
+
+void AST::enterLeaveNamespace(Formatter &out, bool enter) const {
+    std::vector<std::string> packageComponents;
+    getPackageAndVersionComponents(
+            &packageComponents, true /* cpp_compatible */);
+
+    if (enter) {
+        for (const auto &component : packageComponents) {
+            out << "namespace " << component << " {\n";
+        }
+    } else {
+        for (auto it = packageComponents.rbegin();
+                it != packageComponents.rend();
+                ++it) {
+            out << "}  // namespace " << *it << "\n";
+        }
+    }
+}
+
+status_t AST::generateInterfaceHeader() const {
+    const std::string packagePath =
+        mCoordinator->getPackagePath(mPackage, true /* relative */);
+
+    std::string path = "/tmp/android/hardware/";
+    path.append(packagePath);
+
+    std::string ifaceName;
+    bool isInterface = true;
+    if (!AST::isInterface(&ifaceName)) {
+        ifaceName = "types";
+        isInterface = false;
+    }
+    path.append(ifaceName);
+    path.append(".h");
+
+    CHECK(MakeParentHierarchy(path));
+    FILE *file = fopen(path.c_str(), "w");
+
+    if (file == NULL) {
+        return -errno;
+    }
+
+    Formatter out(file);
+
+    const std::string guard = makeHeaderGuard(ifaceName);
+
+    out << "#ifndef " << guard << "\n";
+    out << "#define " << guard << "\n\n";
+
+    out << "#include <hwbinder/HidlSupport.h>\n";
+
+    if (isInterface) {
+        out << "#include <hwbinder/IBinder.h>\n";
+        out << "#include <hwbinder/IInterface.h>\n";
+        out << "#include <hwbinder/Status.h>\n";
+    }
+
+    out << "#include <utils/NativeHandle.h>\n\n";
+
+    enterLeaveNamespace(out, true /* enter */);
+    out << "\n";
+
+    if (isInterface) {
+        out << "struct "
+            << ifaceName
+            << " : public ::android::hidl::IInterface {\n";
+
+        out.indent();
+
+        out << "DECLARE_HWBINDER_META_INTERFACE(" << ifaceName << ");\n\n";
+    }
+
+    status_t err = emitTypeDeclarations(out);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (isInterface) {
+        const Interface *iface = mRootScope->getInterface();
+
+        out << "enum Call {\n";
+        out.indent();
+
+        bool first = true;
+        for (const auto &method : iface->methods()) {
+            out << upcase(method->name());
+
+            if (first) {
+                out << " = ::android::hidl::IBinder::FIRST_CALL_TRANSACTION";
+                first = false;
+            }
+
+            out << ",\n";
+        }
+
+        out.unindent();
+        out << "};\n\n";
+
+        bool haveCallbacks = false;
+        for (const auto &method : iface->methods()) {
+            const bool returnsValue = !method->results().empty();
+
+            if (!returnsValue) {
+                continue;
+            }
+
+            haveCallbacks = true;
+
+            out << "using "
+                << method->name()
+                << "_cb = std::function<void("
+                << Method::GetSignature(method->results())
+                << ")>;\n";
+        }
+
+        if (haveCallbacks) {
+            out << "\n";
+        }
+
+        for (const auto &method : iface->methods()) {
+            const bool returnsValue = !method->results().empty();
+
+            out << "virtual ::android::hidl::binder::Status "
+                << method->name()
+                << "("
+                << Method::GetSignature(method->args());
+
+            if (returnsValue) {
+                if (!method->args().empty()) {
+                    out << ", ";
+                }
+
+                out << method->name() << "_cb _aidl_cb = nullptr";
+            }
+
+            out << ") = 0;\n";
+        }
+    }
+
+    if (isInterface) {
+        out.unindent();
+
+        out << "};\n";
+    }
+
+    out << "\n";
+    enterLeaveNamespace(out, false /* enter */);
+
+    out << "\n#endif  // " << guard << "\n";
+
+    return OK;
+}
+
+status_t AST::emitTypeDeclarations(Formatter &out) const {
+    return mRootScope->emitTypeDeclarations(out);
+}
+
+status_t AST::generateStubHeader() const {
+    std::string ifaceName;
+    if (!AST::isInterface(&ifaceName)) {
+        // types.hal does not get a stub header.
+        return OK;
+    }
+
+    const std::string packagePath =
+        mCoordinator->getPackagePath(mPackage, true /* relative */);
+
+    // cut off the leading 'I'.
+    const std::string baseName = ifaceName.substr(1);
+
+    std::string path = "/tmp/android/hardware/";
+    path.append(packagePath);
+    path.append("Bn");
+    path.append(baseName);
+    path.append(".h");
+
+    CHECK(MakeParentHierarchy(path));
+    FILE *file = fopen(path.c_str(), "w");
+
+    if (file == NULL) {
+        return -errno;
+    }
+
+    Formatter out(file);
+
+    const std::string guard = makeHeaderGuard("Bn" + baseName);
+
+    out << "#ifndef " << guard << "\n";
+    out << "#define " << guard << "\n\n";
+
+    std::vector<std::string> packageComponents;
+    getPackageAndVersionComponents(
+            &packageComponents, false /* cpp_compatible */);
+
+    out << "#include <";
+    for (const auto &component : packageComponents) {
+        out << component << "/";
+    }
+    out << ifaceName << ".h>\n\n";
+
+    enterLeaveNamespace(out, true /* enter */);
+    out << "\n";
+
+    out << "struct "
+        << "Bn"
+        << baseName
+        << " : public ::android::hidl::BnInterface<"
+        << ifaceName
+        << "> {\n";
+
+    out.indent();
+
+    out << "::android::status_t onTransact(\n";
+    out.indent();
+    out.indent();
+    out << "uint32_t _aidl_code,\n";
+    out << "const ::android::hidl::Parcel &_aidl_data,\n";
+    out << "::android::hidl::Parcel *_aidl_reply,\n";
+    out << "uint32_t _aidl_flags = 0,\n";
+    out << "TransactCallback _aidl_cb = nullptr) override;\n";
+    out.unindent();
+    out.unindent();
+
+    out.unindent();
+
+    out << "};\n\n";
+
+    enterLeaveNamespace(out, false /* enter */);
+
+    out << "\n#endif  // " << guard << "\n";
+
+    return OK;
+}
+
+status_t AST::generateProxyHeader() const {
+    std::string ifaceName;
+    if (!AST::isInterface(&ifaceName)) {
+        // types.hal does not get a proxy header.
+        return OK;
+    }
+
+    const std::string packagePath =
+        mCoordinator->getPackagePath(mPackage, true /* relative */);
+
+    // cut off the leading 'I'.
+    const std::string baseName = ifaceName.substr(1);
+
+    std::string path = "/tmp/android/hardware/";
+    path.append(packagePath);
+    path.append("Bp");
+    path.append(baseName);
+    path.append(".h");
+
+    CHECK(MakeParentHierarchy(path));
+    FILE *file = fopen(path.c_str(), "w");
+
+    if (file == NULL) {
+        return -errno;
+    }
+
+    Formatter out(file);
+
+    const std::string guard = makeHeaderGuard("Bp" + baseName);
+
+    out << "#ifndef " << guard << "\n";
+    out << "#define " << guard << "\n\n";
+
+    std::vector<std::string> packageComponents;
+    getPackageAndVersionComponents(
+            &packageComponents, false /* cpp_compatible */);
+
+    out << "#include <";
+    for (const auto &component : packageComponents) {
+        out << component << "/";
+    }
+    out << ifaceName << ".h>\n\n";
+
+    enterLeaveNamespace(out, true /* enter */);
+    out << "\n";
+
+    out << "struct "
+        << "Bp"
+        << baseName
+        << " : public ::android::hidl::BpInterface<"
+        << ifaceName
+        << "> {\n";
+
+    out.indent();
+
+    out << "explicit Bp"
+        << baseName
+        << "(const ::android::sp<::android::hidl::IBinder> &_aidl_impl);"
+        << "\n\n";
+
+    const Interface *iface = mRootScope->getInterface();
+
+    for (const auto &method : iface->methods()) {
+        const bool returnsValue = !method->results().empty();
+
+        out << "::android::hidl::binder::Status "
+            << method->name()
+            << "("
+            << Method::GetSignature(method->args());
+
+        if (returnsValue) {
+            if (!method->args().empty()) {
+                out << ", ";
+            }
+
+            out << method->name() << "_cb _aidl_cb";
+        }
+
+        out << ") override;\n";
+    }
+
+    out.unindent();
+
+    out << "};\n\n";
+
+    enterLeaveNamespace(out, false /* enter */);
+
+    out << "\n#endif  // " << guard << "\n";
+
+    return OK;
+}
+
+status_t AST::generateAllSource() const {
+    const std::string packagePath =
+        mCoordinator->getPackagePath(mPackage, true /* relative */);
+
+    std::string path = "/tmp/android/hardware/";
+    path.append(packagePath);
+
+    std::string ifaceName;
+    std::string baseName;
+
+    bool isInterface = true;
+    if (!AST::isInterface(&ifaceName)) {
+        baseName = "types";
+        isInterface = false;
+    } else {
+        baseName = ifaceName.substr(1); // cut off the leading 'I'.
+    }
+
+    path.append(baseName);
+
+    if (baseName != "types") {
+        path.append("All");
+    }
+
+    path.append(".cpp");
+
+    CHECK(MakeParentHierarchy(path));
+    FILE *file = fopen(path.c_str(), "w");
+
+    if (file == NULL) {
+        return -errno;
+    }
+
+    Formatter out(file);
+
+    std::vector<std::string> packageComponents;
+    getPackageAndVersionComponents(
+            &packageComponents, false /* cpp_compatible */);
+
+    std::string prefix;
+    for (const auto &component : packageComponents) {
+        prefix += component;
+        prefix += "/";
+    }
+
+    if (isInterface) {
+        out << "#include <" << prefix << "/Bp" << baseName << ".h>\n";
+        out << "#include <" << prefix << "/Bn" << baseName << ".h>\n";
+    } else {
+        out << "#include <" << prefix << "types.h>\n";
+    }
+
+    out << "\n";
+
+    enterLeaveNamespace(out, true /* enter */);
+    out << "\n";
+
+    status_t err = generateTypeSource(out, ifaceName);
+
+    if (err == OK && isInterface) {
+        err = generateProxySource(out, baseName);
+    }
+
+    if (err == OK && isInterface) {
+        err = generateStubSource(out, baseName);
+    }
+
+    enterLeaveNamespace(out, false /* enter */);
+
+    return err;
+}
+
+status_t AST::generateTypeSource(
+        Formatter &out, const std::string &ifaceName) const {
+    return mRootScope->emitTypeDefinitions(out, ifaceName);
+}
+
+void AST::emitCppReaderWriter(
+        Formatter &out,
+        const std::string &parcelObj,
+        bool parcelObjIsPointer,
+        const TypedVar *arg,
+        bool isReader,
+        Type::ErrorMode mode) const {
+    const Type &type = arg->type();
+
+    if (isReader) {
+        std::string extra;
+        out << type.getCppResultType(&extra)
+            << " "
+            << arg->name()
+            << extra
+            << ";\n";
+    }
+
+    type.emitReaderWriter(
+            out,
+            arg->name(),
+            parcelObj,
+            parcelObjIsPointer,
+            isReader,
+            mode);
+}
+
+status_t AST::generateProxySource(
+        Formatter &out, const std::string &baseName) const {
+    const std::string klassName = "Bp" + baseName;
+
+    out << klassName
+        << "::"
+        << klassName
+        << "(const ::android::sp<::android::hidl::IBinder> &_aidl_impl)\n";
+
+    out.indent();
+    out.indent();
+
+    out << ": BpInterface"
+        << "<I"
+        << baseName
+        << ">(_aidl_impl) {\n";
+
+    out.unindent();
+    out.unindent();
+    out << "}\n\n";
+
+    const Interface *iface = mRootScope->getInterface();
+
+    for (const auto &method : iface->methods()) {
+        const bool returnsValue = !method->results().empty();
+
+        out << "::android::hidl::binder::Status "
+            << klassName
+            << "::"
+            << method->name()
+            << "("
+            << Method::GetSignature(method->args());
+
+        if (returnsValue) {
+            if (!method->args().empty()) {
+                out << ", ";
+            }
+
+            out << method->name() << "_cb _aidl_cb";
+        }
+
+        out << ") {\n";
+
+        out.indent();
+
+        out << "::android::hidl::Parcel _aidl_data;\n";
+        out << "::android::hidl::Parcel _aidl_reply;\n";
+        out << "::android::status_t _aidl_err;\n\n";
+        out << "::android::hidl::binder::Status _aidl_status;\n";
+
+        out << "_aidl_err = _aidl_data.writeInterfaceToken("
+               "getInterfaceDescriptor());\n";
+
+        out << "if (_aidl_err != ::android::OK) { goto _aidl_error; }\n\n";
+
+        for (const auto &arg : method->args()) {
+            emitCppReaderWriter(
+                    out,
+                    "_aidl_data",
+                    false /* parcelObjIsPointer */,
+                    arg,
+                    false /* reader */,
+                    Type::ErrorMode_Goto);
+        }
+
+        out << "_aidl_err = remote()->transact(I"
+                  << baseName
+                  << "::"
+                  << upcase(method->name())
+                  << ", _aidl_data, &_aidl_reply);\n";
+
+        out << "if (_aidl_err != ::android::OK) { goto _aidl_error; }\n\n";
+
+        out << "_aidl_err = _aidl_status.readFromParcel(_aidl_reply);\n";
+        out << "if (_aidl_err != ::android::OK) { goto _aidl_error; }\n\n";
+
+        out << "if (!_aidl_status.isOk()) { return _aidl_status; }\n\n";
+
+        for (const auto &arg : method->results()) {
+            emitCppReaderWriter(
+                    out,
+                    "_aidl_reply",
+                    false /* parcelObjIsPointer */,
+                    arg,
+                    true /* reader */,
+                    Type::ErrorMode_Goto);
+        }
+
+        if (returnsValue) {
+            out << "if (_aidl_cb != nullptr) {\n";
+            out.indent();
+            out << "_aidl_cb(";
+
+            bool first = true;
+            for (const auto &arg : method->results()) {
+                if (!first) {
+                    out << ", ";
+                }
+
+                if (arg->type().resultNeedsDeref()) {
+                    out << "*";
+                }
+                out << arg->name();
+
+                first = false;
+            }
+
+            out << ");\n";
+            out.unindent();
+            out << "}\n\n";
+        }
+
+        out.unindent();
+        out << "_aidl_error:\n";
+        out.indent();
+        out << "_aidl_status.setFromStatusT(_aidl_err);\n"
+                  << "return _aidl_status;\n";
+
+        out.unindent();
+        out << "}\n\n";
+    }
+
+    return OK;
+}
+
+status_t AST::generateStubSource(
+        Formatter &out, const std::string &baseName) const {
+    out << "IMPLEMENT_HWBINDER_META_INTERFACE("
+        << baseName
+        << ", \""
+        << mPackage.string()
+        << "::I"
+        << baseName
+        << "\");\n\n";
+
+    const std::string klassName = "Bn" + baseName;
+
+    out << "::android::status_t " << klassName << "::onTransact(\n";
+
+    out.indent();
+    out.indent();
+
+    out << "uint32_t _aidl_code,\n"
+        << "const ::android::hidl::Parcel &_aidl_data,\n"
+        << "::android::hidl::Parcel *_aidl_reply,\n"
+        << "uint32_t _aidl_flags,\n"
+        << "TransactCallback _aidl_cb) {\n";
+
+    out.unindent();
+
+    out << "::android::status_t _aidl_err = ::android::OK;\n\n";
+
+    out << "switch (_aidl_code) {\n";
+    out.indent();
+
+    const Interface *iface = mRootScope->getInterface();
+
+    for (const auto &method : iface->methods()) {
+        out << "case Call::" << upcase(method->name()) << ":\n{\n";
+        out.indent();
+
+        status_t err = generateStubSourceForMethod(out, method);
+
+        if (err != OK) {
+            return err;
+        }
+
+        out.unindent();
+        out << "}\n\n";
+    }
+
+    out << "default:\n{\n";
+    out.indent();
+
+    out << "return ::android::hidl::BnInterface<I"
+        << baseName
+        << ">::onTransact(\n";
+
+    out.indent();
+    out.indent();
+
+    out << "_aidl_code, _aidl_data, _aidl_reply, "
+        << "_aidl_flags, _aidl_cb);\n";
+
+    out.unindent();
+    out.unindent();
+
+    out.unindent();
+    out << "}\n";
+
+    out.unindent();
+    out << "}\n\n";
+
+    out << "if (_aidl_err == ::android::UNEXPECTED_NULL) {\n";
+    out.indent();
+    out << "_aidl_err = ::android::hidl::binder::Status::fromExceptionCode(\n";
+    out.indent();
+    out.indent();
+    out << "::android::hidl::binder::Status::EX_NULL_POINTER)\n";
+    out.indent();
+    out.indent();
+    out << ".writeToParcel(_aidl_reply);\n";
+    out.unindent();
+    out.unindent();
+    out.unindent();
+    out.unindent();
+
+    out.unindent();
+    out << "}\n\n";
+
+    out << "return _aidl_err;\n";
+
+    out.unindent();
+    out << "}\n\n";
+
+    return OK;
+}
+
+status_t AST::generateStubSourceForMethod(
+        Formatter &out, const Method *method) const {
+    out << "if (!_aidl_data.checkInterface(this)) {\n";
+    out.indent();
+    out << "_aidl_err = ::android::BAD_TYPE;\n";
+    out << "break;\n";
+    out.unindent();
+    out << "}\n\n";
+
+    for (const auto &arg : method->args()) {
+        emitCppReaderWriter(
+                out,
+                "_aidl_data",
+                false /* parcelObjIsPointer */,
+                arg,
+                true /* reader */,
+                Type::ErrorMode_Break);
+    }
+
+    const bool returnsValue = !method->results().empty();
+
+    if (returnsValue) {
+        out << "bool _aidl_callbackCalled = false;\n\n";
+    }
+
+    out << "::android::hidl::binder::Status _aidl_status(\n";
+    out.indent();
+    out.indent();
+    out << method->name() << "(";
+
+    bool first = true;
+    for (const auto &arg : method->args()) {
+        if (!first) {
+            out << ", ";
+        }
+
+        if (arg->type().resultNeedsDeref()) {
+            out << "*";
+        }
+
+        out << arg->name();
+
+        first = false;
+    }
+
+    if (returnsValue) {
+        if (!first) {
+            out << ", ";
+        }
+
+        out << "[&](";
+
+        first = true;
+        for (const auto &arg : method->results()) {
+            if (!first) {
+                out << ", ";
+            }
+
+            out << "const auto &" << arg->name();
+
+            first = false;
+        }
+
+        out << ") {\n";
+        out.indent();
+        out << "_aidl_callbackCalled = true;\n\n";
+
+        out << "::android::hidl::binder::Status::ok()"
+                  << ".writeToParcel(_aidl_reply);\n\n";
+
+        for (const auto &arg : method->results()) {
+            emitCppReaderWriter(
+                    out,
+                    "_aidl_reply",
+                    true /* parcelObjIsPointer */,
+                    arg,
+                    false /* reader */,
+                    Type::ErrorMode_Ignore);
+        }
+
+        out << "_aidl_cb(*_aidl_reply);\n";
+
+        out.unindent();
+        out << "}\n";
+    }
+
+    out.unindent();
+    out.unindent();
+    out << "));\n\n";
+
+    if (returnsValue) {
+        out << "if (!_aidl_callbackCalled) {\n";
+        out.indent();
+    }
+
+    out << "_aidl_err = _aidl_status.writeToParcel(_aidl_reply);\n";
+
+    if (returnsValue) {
+        out.unindent();
+        out << "}\n\n";
+    }
+
+    out << "break;\n";
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/hidl-gen_l.ll b/hidl-gen_l.ll
index f1424ed..ad5446e 100644
--- a/hidl-gen_l.ll
+++ b/hidl-gen_l.ll
@@ -110,7 +110,7 @@
 
 %%
 
-int yywrap(yyscan_t scanner) {
+int yywrap(yyscan_t) {
     return 1;
 }
 
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 07c9af5..af0e1a0 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -78,11 +78,11 @@
     android::Type *type;
     android::CompoundType *compoundType;
     android::CompoundField *field;
-    android::Vector<android::CompoundField *> *fields;
+    std::vector<android::CompoundField *> *fields;
     android::EnumValue *enumValue;
-    android::Vector<android::EnumValue *> *enumValues;
+    std::vector<android::EnumValue *> *enumValues;
     android::TypedVar *typedVar;
-    android::Vector<android::TypedVar *> *typedVars;
+    std::vector<android::TypedVar *> *typedVars;
     android::Method *method;
     android::CompoundType::Style compoundStyle;
     android::Vector<std::string> *stringVec;
@@ -220,7 +220,7 @@
 method_declaration
     : IDENTIFIER '(' typed_vars ')' ';'
       {
-          $$ = new Method($1, $3);
+          $$ = new Method($1, $3, new std::vector<TypedVar *>);
       }
     | IDENTIFIER '(' typed_vars ')' GENERATES '(' typed_vars ')' ';'
       {
@@ -231,11 +231,11 @@
 typed_vars
     : /* empty */
       {
-          $$ = new Vector<TypedVar *>;
+          $$ = new std::vector<TypedVar *>;
       }
     | typed_var
       {
-          $$ = new Vector<TypedVar *>;
+          $$ = new std::vector<TypedVar *>;
           $$->push_back($1);
       }
     | typed_vars ',' typed_var
@@ -293,7 +293,7 @@
     ;
 
 field_declarations
-    : /* empty */ { $$ = new Vector<CompoundField *>; }
+    : /* empty */ { $$ = new std::vector<CompoundField *>; }
     | field_declarations field_declaration
       {
           $$ = $1;
@@ -360,11 +360,11 @@
 enum_values
     : /* empty */
       {
-          $$ = new Vector<EnumValue *>;
+          $$ = new std::vector<EnumValue *>;
       }
     | enum_value
       {
-          $$ = new Vector<EnumValue *>;
+          $$ = new std::vector<EnumValue *>;
           $$->push_back($1);
       }
     | enum_values ',' enum_value
diff --git a/main.cpp b/main.cpp
index 0bada61..b881589 100644
--- a/main.cpp
+++ b/main.cpp
@@ -25,10 +25,7 @@
         CHECK(fqName.isValid() && fqName.isFullyQualified());
 
         AST *ast = coordinator.parse(fqName);
-
-        if (ast == NULL) {
-            continue;
-        }
+        CHECK(ast != NULL);
 
         Formatter out;
 
@@ -36,6 +33,8 @@
 
         ast->dump(out);
 
+        ast->generateCpp();
+
         delete ast;
         ast = NULL;
     }