Extend hidl-gen to support generate vts file.

b/30762234

TODO: add regression test.

Change-Id: I1c31fd9a85805cd450ea03cc0ccc750a756d1009
diff --git a/AST.h b/AST.h
index 65dd016..da8f655 100644
--- a/AST.h
+++ b/AST.h
@@ -58,6 +58,9 @@
 
     void getImportedPackages(std::set<FQName> *importSet) const;
 
+    status_t generateVts(const std::string &outputPath) const;
+
+
 private:
     Coordinator *mCoordinator;
     Vector<Scope *> mScopePath;
@@ -110,6 +113,7 @@
 
     status_t emitTypeDeclarations(Formatter &out) const;
     status_t emitJavaTypeDeclarations(Formatter &out) const;
+    status_t emitVtsTypeDeclarations(Formatter &out, Vector<Type*> types) const;
 
     DISALLOW_COPY_AND_ASSIGN(AST);
 };
diff --git a/Android.mk b/Android.mk
index 8ecfa50..3dfbb59 100644
--- a/Android.mk
+++ b/Android.mk
@@ -16,6 +16,7 @@
     FQName.cpp                  \
     generateCpp.cpp             \
     generateJava.cpp            \
+    generateVts.cpp             \
     HandleType.cpp              \
     hidl-gen_y.yy               \
     hidl-gen_l.ll               \
diff --git a/Annotation.cpp b/Annotation.cpp
index d5692cf..2cf6495 100644
--- a/Annotation.cpp
+++ b/Annotation.cpp
@@ -6,17 +6,19 @@
 
 namespace android {
 
-Annotation::Annotation(
-        const char *name,
-        KeyedVector<std::string, std::vector<std::string> *> *params)
-    : mName(name),
-      mParamsByName(params) {
+Annotation::Annotation(const char *name,AnnotationParamVector *params)
+        : mName(name),
+          mParamsByName(params) {
 }
 
 std::string Annotation::name() const {
     return mName;
 }
 
+const AnnotationParamVector &Annotation::params() const {
+    return *mParamsByName;
+}
+
 void Annotation::dump(Formatter &out) const {
     out << "@" << mName;
 
diff --git a/Annotation.h b/Annotation.h
index ad98bf9..07c6d83 100644
--- a/Annotation.h
+++ b/Annotation.h
@@ -10,19 +10,20 @@
 namespace android {
 
 struct Formatter;
+using AnnotationParamVector =
+    DefaultKeyedVector<std::string, std::vector<std::string> *>;
 
 struct Annotation {
-    Annotation(
-            const char *name,
-            KeyedVector<std::string, std::vector<std::string> *> *params);
+    Annotation(const char *name, AnnotationParamVector *params);
 
     std::string name() const;
+    const AnnotationParamVector &params() const;
 
     void dump(Formatter &out) const;
 
 private:
     std::string mName;
-    KeyedVector<std::string, std::vector<std::string> *> *mParamsByName;
+    AnnotationParamVector *mParamsByName;
 
     DISALLOW_COPY_AND_ASSIGN(Annotation);
 };
diff --git a/ArrayType.cpp b/ArrayType.cpp
index 3679429..76c85c3 100644
--- a/ArrayType.cpp
+++ b/ArrayType.cpp
@@ -160,5 +160,18 @@
             mDimension);
 }
 
+status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
+    out << "type: TYPE_ARRAY\n" << "vector_value: {\n";
+    out.indent();
+    out << "size: " << mDimension;
+    status_t err = mElementType->emitVtsTypeDeclarations(out);
+    if (err != OK) {
+        return err;
+    }
+    out.unindent();
+    out << "}\n";
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/ArrayType.h b/ArrayType.h
index 0a245f8..1d8ec1f 100644
--- a/ArrayType.h
+++ b/ArrayType.h
@@ -42,6 +42,8 @@
             const std::string &argName,
             bool isReader) const override;
 
+    status_t emitVtsTypeDeclarations(Formatter &out) const override;
+
 private:
     Type *mElementType;
     std::string mDimension;
diff --git a/CompoundType.cpp b/CompoundType.cpp
index e7a0225..0dc85cb 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -298,6 +298,57 @@
     return true;
 }
 
+status_t CompoundType::emitVtsTypeDeclarations(Formatter &out) const {
+    out << "name: \"" << localName() << "\"\n";
+    switch (mStyle) {
+        case STYLE_STRUCT:
+        {
+            out << "type: TYPE_STRUCT\n" << "struct value: {\n";
+            break;
+        }
+        case STYLE_UNION:
+        {
+            out << "type: TYPE_UNION\n" << "union value: {\n";
+            break;
+        }
+        default:
+            break;
+    }
+    out.indent();
+    // Emit declaration for all subtypes.
+    Scope::emitVtsTypeDeclarations(out);
+    // Emit declaration for all fields.
+    for (const auto &field : *mFields) {
+        status_t status = field->type().emitVtsTypeDeclarations(out);
+        if (status != OK) {
+            return status;
+        }
+    }
+    out.unindent();
+    out << "}\n";
+
+    return OK;
+}
+
+status_t CompoundType::emitVtsArgumentType(Formatter &out) const {
+    switch (mStyle) {
+        case STYLE_STRUCT:
+        {
+            out << "type: TYPE_STRUCT\n";
+            break;
+        }
+        case STYLE_UNION:
+        {
+            out << "type: TYPE_UNION\n";
+            break;
+        }
+        default:
+            break;
+    }
+    out << "predefined_type: \"" << localName() << "\"\n";
+    return OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 CompoundField::CompoundField(const char *name, Type *type)
diff --git a/CompoundType.h b/CompoundType.h
index b072b19..495a99e 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -49,6 +49,9 @@
     bool needsEmbeddedReadWrite() const override;
     bool resultNeedsDeref() const override;
 
+    status_t emitVtsTypeDeclarations(Formatter &out) const override;
+    status_t emitVtsArgumentType(Formatter &out) const override;
+
 private:
     Style mStyle;
     std::vector<CompoundField *> *mFields;
diff --git a/EnumType.cpp b/EnumType.cpp
index 2c6f729..3a9a3c2 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -202,6 +202,31 @@
     return OK;
 }
 
+status_t EnumType::emitVtsTypeDeclarations(Formatter &out) const {
+    out << "name: \""
+        << localName()
+        << "\"\n"
+        << "type: TYPE_ENUM\n"
+        << "enum_value: {\n";
+    out.indent();
+    for (const auto &entry : values()) {
+        out << "enumerator: \""
+            << entry->name()
+            << "\"\n"
+            << "value: "
+            << entry->value()
+            << "\n";
+    }
+    out.unindent();
+    out << "}\n";
+    return OK;
+}
+
+status_t EnumType::emitVtsArgumentType(Formatter &out) const {
+    out << "type: TYPE_ENUM\n" << "predefined_type:\"" << localName() << "\"\n";
+    return OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 EnumValue::EnumValue(const char *name, const char *value)
diff --git a/EnumType.h b/EnumType.h
index 6453166..7aa55e5 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -37,6 +37,9 @@
     status_t emitTypeDeclarations(Formatter &out) const override;
     status_t emitJavaTypeDeclarations(Formatter &out) const override;
 
+    status_t emitVtsTypeDeclarations(Formatter &out) const override;
+    status_t emitVtsArgumentType(Formatter &out) const override;
+
 private:
     std::vector<EnumValue *> *mValues;
     Type *mStorageType;
diff --git a/Formatter.cpp b/Formatter.cpp
index 060513c..959c6a8 100644
--- a/Formatter.cpp
+++ b/Formatter.cpp
@@ -2,8 +2,6 @@
 
 #include <assert.h>
 
-using std::string;
-
 namespace android {
 
 Formatter::Formatter(FILE *file)
@@ -28,13 +26,13 @@
     --mIndentDepth;
 }
 
-Formatter &Formatter::operator<<(const string &out) {
+Formatter &Formatter::operator<<(const std::string &out) {
     const size_t len = out.length();
     size_t start = 0;
     while (start < len) {
         size_t pos = out.find("\n", start);
 
-        if (pos == string::npos) {
+        if (pos == std::string::npos) {
             if (mAtStartOfLine) {
                 fprintf(mFile, "%*s", (int)(2 * mIndentDepth), "");
                 mAtStartOfLine = false;
diff --git a/Interface.cpp b/Interface.cpp
index ab117f2..42186af 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -8,7 +8,7 @@
 
 Interface::Interface(
         Interface *super,
-        KeyedVector<std::string, Annotation *> *annotations)
+        AnnotationVector *annotations)
         : mSuperType(super),
           mAnnotationsByName(annotations) {
 }
@@ -29,7 +29,7 @@
     return mMethods;
 }
 
-const KeyedVector<std::string, Annotation *> &Interface::annotations() const {
+const AnnotationVector &Interface::annotations() const {
     return *mAnnotationsByName;
 }
 
@@ -114,5 +114,13 @@
     }
 }
 
+status_t Interface::emitVtsArgumentType(Formatter &out) const {
+    out << "type: TYPE_HIDL_CALLBACK\n"
+        << "predefined_type: \""
+        << localName()
+        << "\"\n";
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/Interface.h b/Interface.h
index a7d9afb..ddff137 100644
--- a/Interface.h
+++ b/Interface.h
@@ -2,6 +2,7 @@
 
 #define INTERFACE_H_
 
+#include "Method.h"
 #include "Scope.h"
 
 #include <utils/KeyedVector.h>
@@ -15,7 +16,7 @@
 struct Interface : public Scope {
     Interface(
             Interface *super,
-            KeyedVector<std::string, Annotation *> *annotations);
+            AnnotationVector *annotations);
 
     void addMethod(Method *method);
 
@@ -25,7 +26,7 @@
 
     const std::vector<Method *> &methods() const;
 
-    const KeyedVector<std::string, Annotation *> &annotations() const;
+    const AnnotationVector &annotations() const;
 
     std::string getCppType(StorageMode mode, std::string *extra) const override;
 
@@ -45,10 +46,12 @@
             const std::string &argName,
             bool isReader) const override;
 
+    status_t emitVtsArgumentType(Formatter &out) const override;
+
 private:
     Interface *mSuperType;
     std::vector<Method *> mMethods;
-    KeyedVector<std::string, Annotation *> *mAnnotationsByName;
+    AnnotationVector *mAnnotationsByName;
 
     DISALLOW_COPY_AND_ASSIGN(Interface);
 };
diff --git a/Method.cpp b/Method.cpp
index 8c140ff..37c71ea 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -9,7 +9,7 @@
 Method::Method(const char *name,
        std::vector<TypedVar *> *args,
        std::vector<TypedVar *> *results,
-       KeyedVector<std::string, Annotation *> *annotations)
+       AnnotationVector *annotations)
     : mName(name),
       mArgs(args),
       mResults(results),
@@ -28,7 +28,7 @@
     return *mResults;
 }
 
-const KeyedVector<std::string, Annotation *> &Method::annotations() const {
+const AnnotationVector &Method::annotations() const {
     return *mAnnotationsByName;
 }
 
diff --git a/Method.h b/Method.h
index e449542..c0bfc6c 100644
--- a/Method.h
+++ b/Method.h
@@ -14,16 +14,19 @@
 struct Type;
 struct TypedVar;
 
+using AnnotationVector =
+        DefaultKeyedVector<std::string, Annotation *>;
+
 struct Method {
     Method(const char *name,
            std::vector<TypedVar *> *args,
            std::vector<TypedVar *> *results,
-           KeyedVector<std::string, Annotation *> *annotations);
+           AnnotationVector *annotations);
 
     std::string name() const;
     const std::vector<TypedVar *> &args() const;
     const std::vector<TypedVar *> &results() const;
-    const KeyedVector<std::string, Annotation *> &annotations() const;
+    const AnnotationVector &annotations() const;
 
     static std::string GetSignature(const std::vector<TypedVar *> &args);
     static std::string GetJavaSignature(const std::vector<TypedVar *> &args);
@@ -34,7 +37,7 @@
     std::string mName;
     std::vector<TypedVar *> *mArgs;
     std::vector<TypedVar *> *mResults;
-    KeyedVector<std::string, Annotation *> *mAnnotationsByName;
+    AnnotationVector *mAnnotationsByName;
 
     DISALLOW_COPY_AND_ASSIGN(Method);
 };
diff --git a/README.md b/README.md
index ccc7250..18978a6 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
 hidl-gen -o output-path -L language (-r interface-root) fqname
 
 output-path: directory to store the output files.
-language: output file for given language. e.g.c++.
+language: output file for given language. e.g.c++, vts..
 
 fqname: fully qualified name of the input files.
 For singe file input, follow the format: package@version::fileName
@@ -26,5 +26,6 @@
 examples:
 
 hidl-gen -o output -L c++ android.hardware.nfc@1.0::INfc.hal
+hidl-gen -o output -L vts android.hardware.nfc@1.0
 hild-gen -o test -L c++ -r android.hardware:/home/android/master/hardware/interfaces android.hardware.nfc@1.0
 ```
diff --git a/ScalarType.cpp b/ScalarType.cpp
index bf111ca..b87168e 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -147,5 +147,15 @@
     handleError(out, mode);
 }
 
+
+status_t ScalarType::emitVtsTypeDeclarations(Formatter &out) const {
+    std::string extra;
+    out << "type: TYPE_SCALAR\n"
+        << "scalar_type: "
+        << getCppType(StorageMode_Stack, &extra)
+        << "\n";
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/ScalarType.h b/ScalarType.h
index 3e84597..a083d54 100644
--- a/ScalarType.h
+++ b/ScalarType.h
@@ -51,6 +51,8 @@
             ErrorMode mode,
             bool needsCast) const;
 
+    status_t emitVtsTypeDeclarations(Formatter &out) const override;
+
 private:
     Kind mKind;
 
diff --git a/Scope.cpp b/Scope.cpp
index ec865af..abad31d 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -109,5 +109,20 @@
     return OK;
 }
 
+
+Vector<Type *> Scope::getSubTypes() const {
+    return mTypes;
+}
+
+status_t Scope::emitVtsTypeDeclarations(Formatter &out) const {
+    for (size_t i = 0; i < mTypes.size(); ++i) {
+        status_t status = mTypes[i]->emitVtsTypeDeclarations(out);
+        if (status != OK) {
+            return status;
+        }
+    }
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/Scope.h b/Scope.h
index 66b11f9..0c3ca68 100644
--- a/Scope.h
+++ b/Scope.h
@@ -37,6 +37,10 @@
     status_t emitTypeDefinitions(
             Formatter &out, const std::string prefix) const override;
 
+    Vector<Type *> getSubTypes() const;
+
+    status_t emitVtsTypeDeclarations(Formatter &out) const override;
+
 private:
     Vector<Type *> mTypes;
     KeyedVector<std::string, size_t> mTypeIndexByName;
diff --git a/StringType.cpp b/StringType.cpp
index ca01687..9e46f94 100644
--- a/StringType.cpp
+++ b/StringType.cpp
@@ -122,5 +122,10 @@
     return true;
 }
 
+status_t StringType::emitVtsTypeDeclarations(Formatter &out) const {
+    out << "type: TYPE_STRING\n";
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/StringType.h b/StringType.h
index 0fc6223..7b78305 100644
--- a/StringType.h
+++ b/StringType.h
@@ -35,6 +35,8 @@
 
     bool needsEmbeddedReadWrite() const override;
     bool resultNeedsDeref() const override;
+
+    status_t emitVtsTypeDeclarations(Formatter &out) const override;
 };
 
 }  // namespace android
diff --git a/Type.cpp b/Type.cpp
index 1e7e2d5..59439c3 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -255,5 +255,13 @@
     out << ");\n";
 }
 
+status_t Type::emitVtsTypeDeclarations(Formatter &) const {
+    return OK;
+}
+
+status_t Type::emitVtsArgumentType(Formatter &out) const {
+    return emitVtsTypeDeclarations(out);
+}
+
 }  // namespace android
 
diff --git a/Type.h b/Type.h
index c24b907..b83f8f3 100644
--- a/Type.h
+++ b/Type.h
@@ -84,6 +84,12 @@
     virtual bool needsEmbeddedReadWrite() const;
     virtual bool resultNeedsDeref() const;
 
+    // Generates type declaration for vts proto file.
+    // TODO (b/30844146): make it a pure virtual method.
+    virtual status_t emitVtsTypeDeclarations(Formatter &out) const;
+    // Generates type declaration as method argument for vts proto file.
+    virtual status_t emitVtsArgumentType(Formatter &out) const;
+
 protected:
     void handleError(Formatter &out, ErrorMode mode) const;
     void handleError2(Formatter &out, ErrorMode mode) const;
diff --git a/VectorType.cpp b/VectorType.cpp
index fc2360e..ed4ddb7 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -167,5 +167,17 @@
     return true;
 }
 
+status_t VectorType::emitVtsTypeDeclarations(Formatter &out) const {
+    out << "type: TYPE_VECTOR\n" << "vector_value: {\n";
+    out.indent();
+    status_t err = mElementType->emitVtsTypeDeclarations(out);
+    if (err != OK) {
+        return err;
+    }
+    out.unindent();
+    out << "}\n";
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/VectorType.h b/VectorType.h
index 905214b..d959ca3 100644
--- a/VectorType.h
+++ b/VectorType.h
@@ -36,7 +36,9 @@
     bool needsEmbeddedReadWrite() const override;
     bool resultNeedsDeref() const override;
 
-private:
+    status_t emitVtsTypeDeclarations(Formatter &out) const override;
+
+ private:
     Type *mElementType;
 
     DISALLOW_COPY_AND_ASSIGN(VectorType);
diff --git a/generateVts.cpp b/generateVts.cpp
new file mode 100644
index 0000000..5c90529
--- /dev/null
+++ b/generateVts.cpp
@@ -0,0 +1,150 @@
+#include "AST.h"
+
+#include "Annotation.h"
+#include "Coordinator.h"
+#include "Formatter.h"
+#include "Interface.h"
+#include "Method.h"
+#include "Scope.h"
+
+#include <android-base/logging.h>
+#include <string>
+#include <vector>
+
+namespace android {
+
+// Remove the double quotas in a string.
+static std::string removeQuotes(const std::string in) {
+    std::string out{in};
+    return out.substr(1, out.size() - 2);
+}
+
+status_t AST::emitVtsTypeDeclarations(
+        Formatter &out,
+        Vector<Type*> types) const {
+    for (const auto& type : types) {
+        out << "attribute: {\n";
+        out.indent();
+        status_t status = type->emitVtsTypeDeclarations(out);
+        if (status != OK) {
+            return status;
+        }
+        out.unindent();
+        out << "}\n\n";
+    }
+    return OK;
+}
+
+status_t AST::generateVts(const std::string &outputPath) const {
+    std::string path = outputPath;
+    path.append(mCoordinator->convertPackageRootToPath(mPackage));
+    path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
+
+    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);
+    path.append(".vts");
+
+    CHECK(Coordinator::MakeParentHierarchy(path));
+    FILE *file = fopen(path.c_str(), "w");
+
+    if (file == NULL) {
+        return -errno;
+    }
+
+    Formatter out(file);
+
+    out << "component_class: HAL_HIDL\n";
+
+    // Get the component_type for interface from annotation.
+    if (isInterface) {
+        const Interface *iface = mRootScope->getInterface();
+        Annotation *annotation = iface->annotations().valueFor("hal_type");
+        if (annotation != NULL) {
+            std::vector<std::string> * values = annotation->params().valueFor(
+                    "type");
+            if (values != NULL) {
+                out << "component_type: "
+                    << removeQuotes(values->at(0))
+                    << "\n";
+            }
+        }
+    }
+
+    out << "component_type_version: " << mPackage.version().substr(1) << "\n";
+    out << "component_name: \""
+        << (isInterface ? ifaceName : "types")
+        << "\"\n\n";
+
+    out << "package: \"" << mPackage.package() << "\"\n\n";
+
+    for (const auto &item : mImportedNames) {
+        out << "import: \"" << item.string() << "\"\n";
+    }
+
+    out << "\n";
+
+    if (isInterface) {
+        const Interface *iface = mRootScope->getInterface();
+        out << "interface: {\n";
+        out.indent();
+
+        status_t status = emitVtsTypeDeclarations(out, iface->getSubTypes());
+        if (status != OK) {
+            return status;
+        }
+
+        for (const auto &method : iface->methods()) {
+            out << "api: {\n";
+            out.indent();
+            out << "name: \"" << method->name() << "\"\n";
+            for (const auto &result : method->results()) {
+                out << "return_type_hidl: {\n";
+                out.indent();
+                status_t status = result->type().emitVtsArgumentType(out);
+                if (status != OK) {
+                    return status;
+                }
+                out.unindent();
+                out << "}\n";
+            }
+            for (const auto &arg : method->args()) {
+                out << "arg: {\n";
+                out.indent();
+                status_t status = arg->type().emitVtsArgumentType(out);
+                if (status != OK) {
+                    return status;
+                }
+                out.unindent();
+                out << "}\n";
+            }
+            out.unindent();
+            out << "}\n\n";
+        }
+
+        out.unindent();
+        out << "}\n";
+    } else {
+        status_t status = emitVtsTypeDeclarations(out,
+                                                  mRootScope->getSubTypes());
+        if (status != OK) {
+            return status;
+        }
+    }
+    return OK;
+}
+
+}  // namespace android
+
+
+
+
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 7fec3b8..09bd4c7 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -92,9 +92,9 @@
     android::CompoundType::Style compoundStyle;
     std::vector<std::string> *stringVec;
     std::pair<std::string, std::vector<std::string> *> *annotationParam;
-    android::KeyedVector<std::string, std::vector<std::string> *> *annotationParams;
+    android::DefaultKeyedVector<std::string, std::vector<std::string> *> *annotationParams;
     android::Annotation *annotation;
-    android::KeyedVector<std::string, android::Annotation *> *annotations;
+    android::DefaultKeyedVector<std::string, android::Annotation *> *annotations;
 }
 
 %%
@@ -102,7 +102,7 @@
 opt_annotations
     : /* empty */
       {
-          $$ = new KeyedVector<std::string, Annotation *>;
+          $$ = new DefaultKeyedVector<std::string, Annotation *>;
       }
     | opt_annotations annotation
       {
@@ -121,7 +121,7 @@
 opt_annotation_params
     : /* empty */
       {
-          $$ = new KeyedVector<std::string, std::vector<std::string> *>;
+          $$ = new DefaultKeyedVector<std::string, std::vector<std::string> *>;
       }
     | '(' annotation_params ')'
       {
@@ -132,7 +132,7 @@
 annotation_params
     : annotation_param
       {
-          $$ = new KeyedVector<std::string, std::vector<std::string> *>;
+          $$ = new DefaultKeyedVector<std::string, std::vector<std::string> *>;
           $$->add($1->first, $1->second);
       }
     | annotation_params ',' annotation_param
diff --git a/main.cpp b/main.cpp
index 9b0bfab..50edcae 100644
--- a/main.cpp
+++ b/main.cpp
@@ -32,8 +32,7 @@
         const char *,
         Coordinator *coordinator,
         const std::string &outputDir,
-        bool java = false) {
-
+        const std::string &lang) {
     CHECK(fqName.isFullyQualified());
 
     AST *ast = coordinator->parse(fqName);
@@ -46,10 +45,17 @@
         return UNKNOWN_ERROR;
     }
 
-    status_t err =
-        java ? ast->generateJava(outputDir) : ast->generateCpp(outputDir);
-
-    return err;
+    if (lang == "c++") {
+        return ast->generateCpp(outputDir);
+    }
+    if (lang == "java") {
+        return ast->generateJava(outputDir);
+    }
+    if (lang == "vts") {
+        return ast->generateVts(outputDir);
+    }
+    // Unknown language.
+    return UNKNOWN_ERROR;
 }
 
 static status_t generateSourcesForPackage(
@@ -57,11 +63,10 @@
         const char *hidl_gen,
         Coordinator *coordinator,
         const std::string &outputDir,
-        bool java = false) {
-
+        const std::string &lang) {
     CHECK(packageFQName.isValid() &&
-          !packageFQName.isFullyQualified() &&
-          packageFQName.name().empty());
+        !packageFQName.isFullyQualified() &&
+        packageFQName.name().empty());
 
     std::vector<FQName> packageInterfaces;
 
@@ -75,8 +80,7 @@
 
     for (const auto &fqName : packageInterfaces) {
         err = generateSourcesForFile(
-                fqName, hidl_gen, coordinator, outputDir, java);
-
+                fqName, hidl_gen, coordinator, outputDir, lang);
         if (err != OK) {
             return err;
         }
@@ -227,7 +231,7 @@
     return OutputHandler::PASS_PACKAGE;
 }
 
-OutputHandler::ValRes validateForCppOrJava(const FQName &fqName) {
+OutputHandler::ValRes validateForSource(const FQName &fqName) {
     if (fqName.package().empty()) {
         fprintf(stderr, "Expecting package name\n");
         return OutputHandler::FAILED;
@@ -246,28 +250,27 @@
 static std::vector<OutputHandler> formats = {
     {"c++",
      true /* mNeedsOutputDir */,
-     validateForCppOrJava,
+     validateForSource,
      [](const FQName &fqName,
         const char *hidl_gen, Coordinator *coordinator,
         const std::string &outputDir) -> status_t {
             if (fqName.isFullyQualified()) {
-                return generateSourcesForFile(fqName,
-                                              hidl_gen,
-                                              coordinator,
-                                              outputDir);
-            }
-            else {
-                return generateSourcesForPackage(fqName,
-                                                 hidl_gen,
-                                                 coordinator,
-                                                 outputDir);
+                        return generateSourcesForFile(fqName,
+                                                      hidl_gen,
+                                                      coordinator,
+                                                      outputDir, "c++");
+            } else {
+                        return generateSourcesForPackage(fqName,
+                                                         hidl_gen,
+                                                         coordinator,
+                                                         outputDir, "c++");
             }
         }
     },
 
     {"java",
      true /* mNeedsOutputDir */,
-     validateForCppOrJava,
+     validateForSource,
      [](const FQName &fqName,
         const char *hidl_gen, Coordinator *coordinator,
         const std::string &outputDir) -> status_t {
@@ -275,19 +278,38 @@
                 return generateSourcesForFile(fqName,
                                               hidl_gen,
                                               coordinator,
-                                              outputDir,
-                                              true /* java */);
+                                              outputDir, "java");
             }
             else {
                 return generateSourcesForPackage(fqName,
                                                  hidl_gen,
                                                  coordinator,
-                                                 outputDir,
-                                                 true /* java */);
+                                                 outputDir, "java");
             }
         }
     },
 
+    {"vts",
+     true,
+     validateForSource,
+     [](const FQName &fqName,
+        const char * hidl_gen,
+        Coordinator *coordinator,
+        const std::string &outputDir) -> status_t {
+            if (fqName.isFullyQualified()) {
+                return generateSourcesForFile(fqName,
+                                              hidl_gen,
+                                              coordinator,
+                                              outputDir, "vts");
+            } else {
+                return generateSourcesForPackage(fqName,
+                                                 hidl_gen,
+                                                 coordinator,
+                                                 outputDir, "vts");
+            }
+       }
+    },
+
     {"makefile",
      false /* mNeedsOutputDir */,
      validateForMakefile,
diff --git a/test/data/android/hardware/nfc/1.0/Nfc.vts b/test/data/android/hardware/nfc/1.0/Nfc.vts
new file mode 100644
index 0000000..6d70ff6
--- /dev/null
+++ b/test/data/android/hardware/nfc/1.0/Nfc.vts
@@ -0,0 +1,83 @@
+component_class: HAL_HIDL
+component_type: NFC
+component_type_version: 1.0
+component_name: "INfc"
+
+package: "android.hardware.nfc"
+
+import: "android.hardware.nfc@1.0::INfcClientCallback"
+import: "android.hardware.nfc@1.0::types"
+
+interface: {
+  api: {
+    name: "open"
+    return_type_hidl: {
+      type: TYPE_SCALAR
+      scalar_type: int32_t
+    }
+    arg: {
+      type: TYPE_HIDL_CALLBACK
+      predefined_type: "INfcClientCallback"
+    }
+  }
+
+  api: {
+    name: "write"
+    return_type_hidl: {
+      type: TYPE_SCALAR
+      scalar_type: int32_t
+    }
+    arg: {
+      type: TYPE_STRUCT
+      predefined_type: "nfc_data_t"
+    }
+  }
+
+  api: {
+    name: "core_initialized"
+    return_type_hidl: {
+      type: TYPE_SCALAR
+      scalar_type: int32_t
+    }
+    arg: {
+      type: TYPE_VECTOR
+      vector_value: {
+        type: TYPE_SCALAR
+        scalar_type: uint8_t
+      }
+    }
+  }
+
+  api: {
+    name: "pre_discover"
+    return_type_hidl: {
+      type: TYPE_SCALAR
+      scalar_type: int32_t
+    }
+  }
+
+  api: {
+    name: "close"
+    return_type_hidl: {
+      type: TYPE_SCALAR
+      scalar_type: int32_t
+    }
+  }
+
+  api: {
+    name: "control_granted"
+    return_type_hidl: {
+      type: TYPE_SCALAR
+      scalar_type: int32_t
+    }
+  }
+
+  api: {
+    name: "power_cycle"
+    return_type_hidl: {
+      type: TYPE_SCALAR
+      scalar_type: int32_t
+    }
+  }
+
+}
diff --git a/test/data/android/hardware/nfc/1.0/NfcClientCallback.vts b/test/data/android/hardware/nfc/1.0/NfcClientCallback.vts
new file mode 100644
index 0000000..fb34126
--- /dev/null
+++ b/test/data/android/hardware/nfc/1.0/NfcClientCallback.vts
@@ -0,0 +1,31 @@
+component_class: HAL_HIDL
+component_type: NFC
+component_type_version: 1.0
+component_name: "INfcClientCallback"
+
+package: "android.hardware.nfc"
+
+import: "android.hardware.nfc@1.0::types"
+
+interface: {
+  api: {
+    name: "sendEvent"
+    arg: {
+      type: TYPE_ENUM
+      predefined_type:"nfc_event_t"
+    }
+    arg: {
+      type: TYPE_ENUM
+      predefined_type:"nfc_status_t"
+    }
+  }
+
+  api: {
+    name: "sendData"
+    arg: {
+      type: TYPE_STRUCT
+      predefined_type: "nfc_data_t"
+    }
+  }
+
+}
diff --git a/test/data/android/hardware/nfc/1.0/types.vts b/test/data/android/hardware/nfc/1.0/types.vts
new file mode 100644
index 0000000..9645c79
--- /dev/null
+++ b/test/data/android/hardware/nfc/1.0/types.vts
@@ -0,0 +1,57 @@
+component_class: HAL_HIDL
+component_type_version: 1.0
+component_name: "types"
+
+package: "android.hardware.nfc"
+
+
+attribute: {
+  name: "nfc_event_t"
+  type: TYPE_ENUM
+  enum_value: {
+    enumerator: "HAL_NFC_OPEN_CPLT_EVT"
+    value: 0
+    enumerator: "HAL_NFC_CLOSE_CPLT_EVT"
+    value: 1
+    enumerator: "HAL_NFC_POST_INIT_CPLT_EVT"
+    value: 2
+    enumerator: "HAL_NFC_PRE_DISCOVER_CPLT_EVT"
+    value: 3
+    enumerator: "HAL_NFC_REQUEST_CONTROL_EVT"
+    value: 4
+    enumerator: "HAL_NFC_RELEASE_CONTROL_EVT"
+    value: 5
+    enumerator: "HAL_NFC_ERROR_EVT"
+    value: 6
+  }
+}
+
+attribute: {
+  name: "nfc_status_t"
+  type: TYPE_ENUM
+  enum_value: {
+    enumerator: "HAL_NFC_STATUS_OK"
+    value: 0
+    enumerator: "HAL_NFC_STATUS_FAILED"
+    value: 1
+    enumerator: "HAL_NFC_STATUS_ERR_TRANSPORT"
+    value: 2
+    enumerator: "HAL_NFC_STATUS_ERR_CMD_TIMEOUT"
+    value: 3
+    enumerator: "HAL_NFC_STATUS_REFUSED"
+    value: 4
+  }
+}
+
+attribute: {
+  name: "nfc_data_t"
+  type: TYPE_STRUCT
+  struct value: {
+    type: TYPE_VECTOR
+    vector_value: {
+      type: TYPE_SCALAR
+      scalar_type: uint8_t
+    }
+  }
+}
+