Merge "Add rel no in csv files"
diff --git a/tools/release-parser/Android.mk b/tools/release-parser/Android.mk
index d7071c1..aed8583 100644
--- a/tools/release-parser/Android.mk
+++ b/tools/release-parser/Android.mk
@@ -27,18 +27,15 @@
 
 LOCAL_JAR_MANIFEST := MANIFEST.mf
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-  compatibility-host-util \
-  dexlib2
-
 LOCAL_MODULE := release-parser
 
 # This tool is not checking any dependencies or metadata, so all of the
 # dependencies of all of the tests must be on its classpath. This is
 # super fragile.
 LOCAL_STATIC_JAVA_LIBRARIES += \
-  tradefed \
+  compatibility-host-util \
   hosttestlib \
-  platformprotos
+  dexlib2 \
+  tradefed
 
 include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/tools/release-parser/proto/release.proto b/tools/release-parser/proto/release.proto
index 457d1f6..569966f 100644
--- a/tools/release-parser/proto/release.proto
+++ b/tools/release-parser/proto/release.proto
@@ -29,23 +29,73 @@
     string value =3;
 }
 
-message ConfigMetadata {
+message TestModuleConfig {
     string module_name = 1;
     string component = 2;
-    repeated Option options = 3;
+    string description = 3;
+    repeated Option options = 4;
 
     message TargetPreparer {
         string test_class = 1;
         repeated Option options = 2;
     }
-    repeated TargetPreparer target_preparers = 4;
+    repeated TargetPreparer target_preparers = 5;
+    repeated string test_file_names = 6;
 
     message TestClass {
         string test_class = 1;
         string package = 2;
         repeated Option options = 3;
     }
-    repeated TestClass test_classes = 5;
+    repeated TestClass test_classes = 7;
+    repeated string test_jars = 8;
+}
+
+// An entry in a release
+message Entry {
+    // Name
+    string name = 1;
+
+    enum EntryType {
+        FOLDER = 0;
+        FILE = 1;
+        CONFIG = 2;
+        JAR = 3;
+        APK = 4;
+        EXE = 5;
+        SO = 6;
+    }
+    // Type
+    EntryType type = 2;
+
+    // Size
+    int64 size = 3;
+    // Content ID
+    string content_id = 4;
+    // Parent folder
+    string parent_folder = 5;
+    // Relative path
+    string relative_path = 6;
+
+    // TestModule.config message
+    TestModuleConfig test_module_config = 7;
+}
+
+message ReleaseContent {
+    // Name
+    string name = 1;
+    // Version
+    string version = 2;
+    // Build Number
+    string build_number = 3;
+    // Content ID
+    string content_id = 4;
+    string fullname = 5;
+    string target_arch = 6;
+    string test_suite_tradefed = 7;
+    // File Entries
+    repeated Entry file_entries = 8;
+    repeated string known_failures = 9;
 }
 
 message Annotation {
@@ -59,117 +109,79 @@
     repeated Element elements = 3;
 }
 
+enum TestClassType {
+    UNKNOWN = 0;
+    JUNIT3 = 1;
+    JUNIT4 = 2;
+    PARAMETERIZED = 3;
+    JAVAHOST = 4;
+}
+
 message TestSuite {
     string name = 1;
-
-    message Package {
-        string name = 1;
-
-        enum Type {
-            ANDROIDJUNIT = 0;
-            JAVAHOST = 1;
-            GTEST = 2;
-            DEQP = 3;
-            LIBCORE = 4;
-            DALVIK = 5;
-        }
-        Type type = 2;
-
-        message Class {
-            string name = 1;
-            string type = 2;
-            string super_class = 3;
-            string interface = 4;
-
-            enum ClassType {
-                UNKNOWN = 0;
-                JUNIT3 = 1;
-                JUNIT4 = 2;
-                PARAMETERIZED = 3;
-                JAVAHOST = 4;
-            }
-
-            ClassType class_type = 5;
-            repeated Annotation annotations = 6;
-
-            message Method {
-                string defining_class = 1;
-                string name = 2;
-                string parameters = 3;
-                string return_type = 4;
-                int32 access_flags = 5;
-                repeated Annotation annotations = 6;
-            }
-            repeated Method methods = 7;
-
-            message Field {
-                string defining_class = 1;
-                string name = 2;
-                string type = 3;
-                int32 access_flags = 4;
-                string initial_value = 5;
-                repeated Annotation annotations = 6;
-            }
-            repeated Field fields = 8;
-            string apk = 9;
-        }
-        repeated Class classes = 3;
-        string op_codes = 4;
-    }
-    repeated Package packages = 2;
-}
-
-// target File Metadata for e.g. config, apk, jar, exe, so
-message FileMetadata {
-    string description = 1;
-    ConfigMetadata config_metadata = 2;
-}
-
-// An entry in a release
-message Entry {
-    // Entry ID
-    string id = 1;
-    // Name
-    string name = 2;
-
-    enum EntryType {
-        FOLDER = 0;
-        FILE = 1;
-        CONFIG = 2;
-        JAR = 3;
-        APK = 4;
-        EXE = 5;
-        SO = 6;
-    }
-
-    // Type
-    EntryType type = 3;
-    // Size
-    int64 size = 4;
-    // Content ID
-    string content_id = 5;
-    // Parent entry ID
-    string parent_id = 6;
-    // Relative path
-    string relative_path = 7;
-
-    FileMetadata file_metadata = 8;
-}
-
-message ReleaseContent {
-    // Name
-    string name = 1;
     // Version
     string version = 2;
-    // Build ID
+    // Build Number
     string build_number = 3;
     // Content ID
     string content_id = 4;
-    string fullname = 5;
-    string target_arch = 6;
-    string test_suite_tradefed = 7;
-    // File Entries
-    repeated Entry file_entries = 8;
-    repeated string known_failures = 9;
+
+    enum TestType {
+        UNKNOWN = 0;
+        ANDROIDJUNIT = 1;
+        JAVAHOST = 2;
+        GTEST = 3;
+        LIBCORE = 4;
+        DALVIK = 5;
+        DEQP = 6;
+    }
+
+    message Module {
+        string name = 1;
+        string config_file = 2;
+        TestType test_type = 3;
+        string test_class = 4;
+
+        message Package {
+            string name = 1;
+            string package_file = 2;
+            string content_id = 3;
+            string op_codes = 4;
+
+            message Class {
+                string name = 1;
+                string type = 2;
+                string super_class = 3;
+                string interface = 4;
+                TestClassType test_class_type = 5;
+                repeated Annotation annotations = 6;
+
+                message Method {
+                    string defining_class = 1;
+                    string name = 2;
+                    string parameters = 3;
+                    string return_type = 4;
+                    int32 access_flags = 5;
+                    string known_failure_filter = 6;
+                    repeated Annotation annotations = 7;
+                }
+                repeated Method methods = 7;
+
+                message Field {
+                    string defining_class = 1;
+                    string name = 2;
+                    string type = 3;
+                    int32 access_flags = 4;
+                    string initial_value = 5;
+                    repeated Annotation annotations = 6;
+                }
+                repeated Field fields = 8;
+            }
+            repeated Class classes = 5;
+        }
+        repeated Package packages = 5;
+    }
+    repeated Module modules = 5;
 }
+
 // [END messages]
diff --git a/tools/release-parser/src/com/android/cts/releaseparser/Main.java b/tools/release-parser/src/com/android/cts/releaseparser/Main.java
index 9a35103..ab176ef 100644
--- a/tools/release-parser/src/com/android/cts/releaseparser/Main.java
+++ b/tools/release-parser/src/com/android/cts/releaseparser/Main.java
@@ -31,6 +31,7 @@
             "Usage: java -jar releaseparser.jar [-options] <folder> [args...]\n"
                     + "           to prase a release content in the folder\n"
                     + "Options:\n"
+                    + "\t-a API#\t API Level, e.g. 27 \n"
                     + "\t-i PATH\t path to a release folder \n"
                     + "\t-o PATH\t path to output files \n";
 
@@ -56,6 +57,7 @@
         String relNameVer;
         String relFolder = "";
         String outputPath = "";
+        int apiL = 27;
 
         for (int i = 0; i < args.length; i++) {
             if (args[i].startsWith("-")) {
@@ -73,6 +75,8 @@
                     if (!file.isDirectory()) {
                         printUsage();
                     }
+                } else if ("-a".equals(args[i])) {
+                    apiL = Integer.parseInt(getExpectedArg(args, ++i));
                 } else {
                     printUsage();
                 }
@@ -85,17 +89,24 @@
 
         ReleaseParser relParser = new ReleaseParser(relFolder);
         relNameVer = relParser.getRelNameVer();
-        relParser.writeCsvFile(
-                Paths.get(outputPath, String.format("%s-RC.csv", relNameVer)).toString());
+        relParser.writeRelesaeContentCsvFile(
+                relNameVer,
+                Paths.get(outputPath, String.format("%s-ReleaseContent.csv", relNameVer))
+                        .toString());
+        relParser.writeTestModuleConfigCsvFile(
+                relNameVer,
+                Paths.get(outputPath, String.format("%s-TestModuleConfig.csv", relNameVer))
+                        .toString());
         relParser.writeKnownFailureCsvFile(
-                Paths.get(outputPath, String.format("%s-KF.csv", relNameVer)).toString());
+                relNameVer,
+                Paths.get(outputPath, String.format("%s-KnownFailure.csv", relNameVer)).toString());
 
         // Write release content message to disk.
         ReleaseContent relContent = relParser.getReleaseContent();
         try {
             FileOutputStream output =
                     new FileOutputStream(
-                            Paths.get(outputPath, String.format("%s-RC.pb", relNameVer))
+                            Paths.get(outputPath, String.format("%s-ReleaseContent.pb", relNameVer))
                                     .toString());
             try {
                 relContent.writeTo(output);
@@ -106,18 +117,20 @@
             System.err.println("IOException:" + e.getMessage());
         }
 
-        TestSuiteParser tsParser = new TestSuiteParser(relContent, relFolder);
+        TestSuiteParser tsParser = new TestSuiteParser(relContent, relFolder, apiL);
         tsParser.writeCsvFile(
-                Paths.get(outputPath, String.format("%s-TC.csv", relNameVer)).toString());
+                relNameVer,
+                Paths.get(outputPath, String.format("%s-TestCase.csv", relNameVer)).toString());
         tsParser.writeSummaryCsvFile(
-                Paths.get(outputPath, String.format("%s-TS.csv", relNameVer)).toString());
+                relNameVer,
+                Paths.get(outputPath, String.format("%s-TestSummary.csv", relNameVer)).toString());
 
         // Write test suite content message to disk.
         TestSuite testSuite = tsParser.getTestSuite();
         try {
             FileOutputStream output =
                     new FileOutputStream(
-                            Paths.get(outputPath, String.format("%s-TC.pb", relNameVer))
+                            Paths.get(outputPath, String.format("%s-TestSuite.pb", relNameVer))
                                     .toString());
             try {
                 testSuite.writeTo(output);
diff --git a/tools/release-parser/src/com/android/cts/releaseparser/ReleaseParser.java b/tools/release-parser/src/com/android/cts/releaseparser/ReleaseParser.java
index 547e8ad..a13e16e 100644
--- a/tools/release-parser/src/com/android/cts/releaseparser/ReleaseParser.java
+++ b/tools/release-parser/src/com/android/cts/releaseparser/ReleaseParser.java
@@ -92,6 +92,13 @@
             mRelContentBuilder = ReleaseContent.newBuilder();
             // also add the root folder entry
             Entry.Builder fBuilder = parseFolder(mFolderPath);
+            fBuilder.setName(
+                    String.format(
+                            "%s-%s-%s",
+                            mRelContentBuilder.getName(),
+                            mRelContentBuilder.getVersion(),
+                            mRelContentBuilder.getBuildNumber()));
+            fBuilder.setParentFolder(mFolderPath);
             mRelContentBuilder.addFileEntries(fBuilder);
         }
         return mRelContentBuilder.build();
@@ -100,29 +107,28 @@
     // Parse all files in a folder, add them to mRelContentBuilder.fileEntry and return the foler entry builder
     private Entry.Builder parseFolder(String fPath) {
         Entry.Builder folderEntry = Entry.newBuilder();
-
         File folder = new File(fPath);
         Path folderPath = Paths.get(folder.getAbsolutePath());
         String folderRelativePath = mRootPath.relativize(folderPath).toString();
-        String folderId = getId(folderRelativePath);
         File[] fileList = folder.listFiles();
         Long folderSize = 0L;
         List<Entry> entryList = new ArrayList<Entry>();
+
+        // walks through all files
         for (File file : fileList) {
             if (file.isFile()) {
                 String fileRelativePath =
                         mRootPath.relativize(Paths.get(file.getAbsolutePath())).toString();
                 Entry.Builder fileEntry = Entry.newBuilder();
-                fileEntry.setId(getId(fileRelativePath));
                 fileEntry.setName(file.getName());
                 fileEntry.setSize(file.length());
                 fileEntry.setContentId(getFileContentId(file));
                 fileEntry.setRelativePath(fileRelativePath);
-                fileEntry.setParentId(folderId);
+                fileEntry.setParentFolder(folderRelativePath);
                 try {
-                    FileMetadata fMetadata = parseFileMetadata(fileEntry, file);
-                    if (null != fMetadata) {
-                        fileEntry.setFileMetadata(fMetadata);
+                    TestModuleConfig tmConfig = parseTestModuleConfig(fileEntry, file);
+                    if (null != tmConfig) {
+                        fileEntry.setTestModuleConfig(tmConfig);
                     }
                     // get [cts]-known-failures.xml
                     if (file.getName().endsWith(TEST_SUITE_TRADEFED_TAG)) {
@@ -143,14 +149,14 @@
                 entryList.add(fileEntry.build());
                 folderSize += file.length();
             } else if (file.isDirectory()) {
+                // Checks subfolders
                 Entry.Builder subFolderEntry = parseFolder(file.getAbsolutePath());
-                subFolderEntry.setParentId(folderId);
+                subFolderEntry.setParentFolder(folderRelativePath);
                 mRelContentBuilder.addFileEntries(subFolderEntry);
-                folderSize += subFolderEntry.getSize();
                 entryList.add(subFolderEntry.build());
+                folderSize += subFolderEntry.getSize();
             }
         }
-        folderEntry.setId(folderId);
         folderEntry.setName(folderRelativePath);
         folderEntry.setSize(folderSize);
         folderEntry.setType(Entry.EntryType.FOLDER);
@@ -160,7 +166,7 @@
     }
 
     // Parse a file
-    private static FileMetadata parseFileMetadata(Entry.Builder fEntry, File file)
+    private static TestModuleConfig parseTestModuleConfig(Entry.Builder fEntry, File file)
             throws Exception {
         if (file.getName().endsWith(CONFIG_EXT_TAG)) {
             fEntry.setType(Entry.EntryType.CONFIG);
@@ -178,7 +184,7 @@
         return null;
     }
 
-    private static FileMetadata parseConfigFile(File file) throws Exception {
+    private static TestModuleConfig parseConfigFile(File file) throws Exception {
         XMLReader xmlReader = XMLReaderFactory.createXMLReader();
         TestModuleConfigHandler testModuleXmlHandler = new TestModuleConfigHandler(file.getName());
         xmlReader.setContentHandler(testModuleXmlHandler);
@@ -186,7 +192,7 @@
         try {
             fileReader = new FileReader(file);
             xmlReader.parse(new InputSource(fileReader));
-            return testModuleXmlHandler.getFileMetadata();
+            return testModuleXmlHandler.getTestModuleConfig();
         } finally {
             if (null != fileReader) {
                 fileReader.close();
@@ -229,99 +235,24 @@
         return id;
     }
 
-    private static String getId(String name) {
-        String id = null;
-        try {
-            MessageDigest md = MessageDigest.getInstance("SHA-256");
-            md.update(name.getBytes(StandardCharsets.UTF_8));
-            // Converts to Base64 String
-            id = Base64.getEncoder().encodeToString(md.digest());
-        } catch (NoSuchAlgorithmException e) {
-            System.err.println("NoSuchAlgorithmException:" + e.getMessage());
-        }
-        return id;
-    }
-
-    // write releaes content to a CSV file
-    public void writeCsvFile(String csvFile) {
+    // writes releaes content to a CSV file
+    public void writeRelesaeContentCsvFile(String relNameVer, String csvFile) {
         ReleaseContent relContent = getReleaseContent();
         try {
             FileWriter fWriter = new FileWriter(csvFile);
             PrintWriter pWriter = new PrintWriter(fWriter);
             //Header
-            pWriter.printf(
-                    "type,name,size,relative path,id,content id,parent id,description,test class");
-            // test class header
-            pWriter.printf(
-                    ",%s,%s,%s,%s,%s",
-                    RUNTIME_HIT_TAG,
-                    PACKAGE_TAG,
-                    JAR_NAME_TAG,
-                    NATIVE_TEST_DEVICE_PATH_TAG,
-                    MODULE_TAG);
-            // target preparer header
-            pWriter.printf(",%s,%s\n", TEST_FILE_NAME_TAG, PUSH_TAG);
-            int i = 1;
+            pWriter.printf("release,type,name,size,relative_path,content_id,parent_folder\n");
             for (Entry entry : relContent.getFileEntriesList()) {
                 pWriter.printf(
-                        "%s,%s,%d,%s,%s,%s,%s",
+                        "%s,%s,%s,%d,%s,%s,%s\n",
+                        relNameVer,
                         entry.getType(),
                         entry.getName(),
                         entry.getSize(),
                         entry.getRelativePath(),
-                        entry.getId(),
                         entry.getContentId(),
-                        entry.getParentId());
-
-                if (Entry.EntryType.CONFIG == entry.getType()) {
-                    ConfigMetadata config = entry.getFileMetadata().getConfigMetadata();
-                    pWriter.printf(",%s", entry.getFileMetadata().getDescription());
-                    List<Option> optList;
-                    List<ConfigMetadata.TestClass> testClassesList = config.getTestClassesList();
-                    String rtHit = "";
-                    String pkg = "";
-                    String jar = "";
-                    String ntdPath = "";
-                    String module = "";
-
-                    for (ConfigMetadata.TestClass tClass : testClassesList) {
-                        pWriter.printf(",%s", tClass.getTestClass());
-                        optList = tClass.getOptionsList();
-                        for (Option opt : optList) {
-                            if (RUNTIME_HIT_TAG.equalsIgnoreCase(opt.getName())) {
-                                rtHit = rtHit + opt.getValue() + " ";
-                            } else if (PACKAGE_TAG.equalsIgnoreCase(opt.getName())) {
-                                pkg = pkg + opt.getValue() + " ";
-                            } else if (JAR_NAME_TAG.equalsIgnoreCase(opt.getName())) {
-                                jar = jar + opt.getValue() + " ";
-                            } else if (NATIVE_TEST_DEVICE_PATH_TAG.equalsIgnoreCase(
-                                    opt.getName())) {
-                                ntdPath = ntdPath + opt.getValue() + " ";
-                            } else if (MODULE_TAG.equalsIgnoreCase(opt.getName())) {
-                                module = module + opt.getValue() + " ";
-                            }
-                        }
-                    }
-                    pWriter.printf(
-                            ",%s,%s,%s,%s,%s",
-                            rtHit.trim(), pkg.trim(), jar.trim(), module.trim(), ntdPath.trim());
-
-                    List<ConfigMetadata.TargetPreparer> tPrepList = config.getTargetPreparersList();
-                    String testFile = "";
-                    String pushList = "";
-                    for (ConfigMetadata.TargetPreparer tPrep : tPrepList) {
-                        optList = tPrep.getOptionsList();
-                        for (Option opt : optList) {
-                            if (TEST_FILE_NAME_TAG.equalsIgnoreCase(opt.getName())) {
-                                testFile = testFile + opt.getValue() + " ";
-                            } else if (PUSH_TAG.equalsIgnoreCase(opt.getName())) {
-                                pushList = pushList + opt.getValue() + " ";
-                            }
-                        }
-                    }
-                    pWriter.printf(",%s,%s", testFile.trim(), pushList.trim());
-                }
-                pWriter.printf("\n");
+                        entry.getParentFolder());
             }
             pWriter.flush();
             pWriter.close();
@@ -330,16 +261,44 @@
         }
     }
 
-    // write known failures to a CSV file
-    public void writeKnownFailureCsvFile(String csvFile) {
+    // writes test module config content to a CSV file
+    public void writeTestModuleConfigCsvFile(String relNameVer, String csvFile) {
         ReleaseContent relContent = getReleaseContent();
         try {
             FileWriter fWriter = new FileWriter(csvFile);
             PrintWriter pWriter = new PrintWriter(fWriter);
             //Header
-            pWriter.printf("compatibility:exclude-filter\n");
+            pWriter.printf("release,component,module,description,test_file_names,test_jars\n");
+            for (Entry entry : relContent.getFileEntriesList()) {
+                if (Entry.EntryType.CONFIG == entry.getType()) {
+                    TestModuleConfig tmConfig = entry.getTestModuleConfig();
+                    pWriter.printf(
+                            "%s,%s,%s,%s,%s,%s\n",
+                            relNameVer,
+                            tmConfig.getComponent(),
+                            tmConfig.getModuleName(),
+                            tmConfig.getDescription(),
+                            String.join(" ", tmConfig.getTestFileNamesList()),
+                            String.join(" ", tmConfig.getTestJarsList()));
+                }
+            }
+            pWriter.flush();
+            pWriter.close();
+        } catch (IOException e) {
+            System.err.println("IOException:" + e.getMessage());
+        }
+    }
+
+    // writes known failures to a CSV file
+    public void writeKnownFailureCsvFile(String relNameVer, String csvFile) {
+        ReleaseContent relContent = getReleaseContent();
+        try {
+            FileWriter fWriter = new FileWriter(csvFile);
+            PrintWriter pWriter = new PrintWriter(fWriter);
+            //Header
+            pWriter.printf("release,compatibility:exclude-filter\n");
             for (String kf : relContent.getKnownFailuresList()) {
-                pWriter.printf("%s\n", kf);
+                pWriter.printf("%s,%s\n", relNameVer, kf);
             }
             pWriter.flush();
             pWriter.close();
diff --git a/tools/release-parser/src/com/android/cts/releaseparser/TestModuleConfigHandler.java b/tools/release-parser/src/com/android/cts/releaseparser/TestModuleConfigHandler.java
index 5850e09..5251f07 100644
--- a/tools/release-parser/src/com/android/cts/releaseparser/TestModuleConfigHandler.java
+++ b/tools/release-parser/src/com/android/cts/releaseparser/TestModuleConfigHandler.java
@@ -38,16 +38,18 @@
     private static final String VALUE_TAG = "value";
     private static final String MODULE_NAME_TAG = "module-name";
     private static final String GTEST_CLASS_TAG = "com.android.tradefed.testtype.GTest";
+    // com.android.compatibility.common.tradefed.testtype.JarHostTest option
+    private static final String JAR_TAG = "jar";
+    // com.android.tradefed.targetprep.suite.SuiteApkInstaller option
+    private static final String TEST_FILE_NAME_TAG = "test-file-name";
 
-    private FileMetadata.Builder mFileMetadata;
-    private ConfigMetadata.Builder mConfigMetadata;
-    private ConfigMetadata.TestClass.Builder mTestCase;
-    private ConfigMetadata.TargetPreparer.Builder mTargetPreparer;
+    private TestModuleConfig.Builder mTestModuleConfig;
+    private TestModuleConfig.TargetPreparer.Builder mTargetPreparer;
+    private TestModuleConfig.TestClass.Builder mTestCase;
     private String mModuleName = null;
 
     TestModuleConfigHandler(String configFileName) {
-        mFileMetadata = FileMetadata.newBuilder();
-        mConfigMetadata = ConfigMetadata.newBuilder();
+        mTestModuleConfig = TestModuleConfig.newBuilder();
         mTestCase = null;
         mTargetPreparer = null;
         // Default Module Name is the Config File Name
@@ -59,48 +61,65 @@
             throws SAXException {
         super.startElement(uri, localName, name, attributes);
 
-        if (CONFIGURATION_TAG.equalsIgnoreCase(localName)) {
-            if (null != attributes.getValue(DESCRIPTION_TAG)) {
-                mFileMetadata.setDescription(attributes.getValue(DESCRIPTION_TAG));
-            } else {
-                mFileMetadata.setDescription("WARNING: no description.");
-            }
-        } else if (TEST_TAG.equalsIgnoreCase(localName)) {
-            mTestCase = ConfigMetadata.TestClass.newBuilder();
-            mTestCase.setTestClass(attributes.getValue(CLASS_TAG));
-        } else if (TARGET_PREPARER_TAG.equalsIgnoreCase(localName)) {
-            mTargetPreparer = ConfigMetadata.TargetPreparer.newBuilder();
-            mTargetPreparer.setTestClass(attributes.getValue(CLASS_TAG));
-        } else if (OPTION_TAG.equalsIgnoreCase(localName)) {
-            Option.Builder option = Option.newBuilder();
-            option.setName(attributes.getValue(NAME_TAG));
-            option.setValue(attributes.getValue(VALUE_TAG));
-            String keyStr = attributes.getValue(KEY_TAG);
-            if (null != keyStr) {
-                option.setKey(keyStr);
-            }
-            if (null != mTestCase) {
-                mTestCase.addOptions(option);
-                if (GTEST_CLASS_TAG.equalsIgnoreCase(option.getName())) {
-                    mModuleName = option.getValue();
+        switch (localName) {
+            case CONFIGURATION_TAG:
+                if (null != attributes.getValue(DESCRIPTION_TAG)) {
+                    mTestModuleConfig.setDescription(attributes.getValue(DESCRIPTION_TAG));
+                } else {
+                    mTestModuleConfig.setDescription("WARNING: no description.");
                 }
-            } else if (null != mTargetPreparer) {
-                mTargetPreparer.addOptions(option);
-            }
+                break;
+            case TEST_TAG:
+                mTestCase = TestModuleConfig.TestClass.newBuilder();
+                mTestCase.setTestClass(attributes.getValue(CLASS_TAG));
+                break;
+            case TARGET_PREPARER_TAG:
+                mTargetPreparer = TestModuleConfig.TargetPreparer.newBuilder();
+                mTargetPreparer.setTestClass(attributes.getValue(CLASS_TAG));
+                break;
+            case OPTION_TAG:
+                Option.Builder option = Option.newBuilder();
+                option.setName(attributes.getValue(NAME_TAG));
+                option.setValue(attributes.getValue(VALUE_TAG));
+                String keyStr = attributes.getValue(KEY_TAG);
+                if (null != keyStr) {
+                    option.setKey(keyStr);
+                }
+                if (null != mTestCase) {
+                    mTestCase.addOptions(option);
+                    switch (option.getName()) {
+                        case JAR_TAG:
+                            mTestModuleConfig.addTestJars(option.getValue());
+                            break;
+                        case GTEST_CLASS_TAG:
+                            mModuleName = option.getValue();
+                            break;
+                    }
+                } else if (null != mTargetPreparer) {
+                    mTargetPreparer.addOptions(option);
+                    if (TEST_FILE_NAME_TAG.equalsIgnoreCase(option.getName())) {
+                        mTestModuleConfig.addTestFileNames(option.getValue());
+                    }
+                }
+                break;
         }
     }
 
     @Override
     public void endElement(String uri, String localName, String name) throws SAXException {
         super.endElement(uri, localName, name);
-        if (TEST_TAG.equalsIgnoreCase(localName)) {
-            mConfigMetadata.addTestClasses(mTestCase);
-            mTestCase = null;
-        } else if (TARGET_PREPARER_TAG.equalsIgnoreCase(localName)) {
-            mConfigMetadata.addTargetPreparers(mTargetPreparer);
-            mTargetPreparer = null;
-        } else if (CONFIGURATION_TAG.equalsIgnoreCase(localName)) {
-            mFileMetadata.setConfigMetadata(mConfigMetadata);
+        switch (localName) {
+            case CONFIGURATION_TAG:
+                mTestModuleConfig.setModuleName(mModuleName);
+                break;
+            case TARGET_PREPARER_TAG:
+                mTestModuleConfig.addTargetPreparers(mTargetPreparer);
+                mTargetPreparer = null;
+                break;
+            case TEST_TAG:
+                mTestModuleConfig.addTestClasses(mTestCase);
+                mTestCase = null;
+                break;
         }
     }
 
@@ -110,10 +129,10 @@
 
     public String getTestClassName() {
         //return the 1st Test Class
-        return mFileMetadata.getConfigMetadata().getTestClassesList().get(0).getTestClass();
+        return mTestModuleConfig.getTestClassesList().get(0).getTestClass();
     }
 
-    public FileMetadata getFileMetadata() {
-        return mFileMetadata.build();
+    public TestModuleConfig getTestModuleConfig() {
+        return mTestModuleConfig.build();
     }
 }
diff --git a/tools/release-parser/src/com/android/cts/releaseparser/TestSuiteParser.java b/tools/release-parser/src/com/android/cts/releaseparser/TestSuiteParser.java
index c54ae14..2e067eb 100644
--- a/tools/release-parser/src/com/android/cts/releaseparser/TestSuiteParser.java
+++ b/tools/release-parser/src/com/android/cts/releaseparser/TestSuiteParser.java
@@ -49,7 +49,6 @@
 import java.util.jar.JarFile;
 
 class TestSuiteParser {
-    private static final int OPCODE_API = 27;
     // JUNIT3 Test suffix
     private static final String TEST_TAG = "Test;";
     // Some may ends with Tests e.g. cts/tests/tests/accounts/src/android/accounts/cts/AbstractAuthenticatorTests.java
@@ -105,14 +104,13 @@
 
     private final String mFolderPath;
     private ReleaseContent mRelContent;
+    private final int mApiLevel;
     private TestSuite.Builder mTSBuilder;
-    private List<String> mTestApkList;
-    private List<String> mTestClassList;
-    private List<String> mHostTestJarList;
 
-    TestSuiteParser(ReleaseContent relContent, String folder) {
+    TestSuiteParser(ReleaseContent relContent, String folder, int apiL) {
         mFolderPath = folder;
         mRelContent = relContent;
+        mApiLevel = apiL;
     }
 
     public TestSuite getTestSuite() {
@@ -122,99 +120,99 @@
         return mTSBuilder.build();
     }
 
-    // Iterates though all test suite content
     private TestSuite.Builder praseTestSuite() {
         TestSuite.Builder tsBuilder = TestSuite.newBuilder();
 
-        int i = 1;
+        tsBuilder.setName(mRelContent.getName());
+        tsBuilder.setVersion(mRelContent.getVersion());
+        tsBuilder.setBuildNumber(mRelContent.getBuildNumber());
+
+        // Iterates all file
         for (Entry entry : mRelContent.getFileEntriesList()) {
+            // Only parses test module config files
             if (Entry.EntryType.CONFIG == entry.getType()) {
-                TestSuite.Package.Type pType = null;
-                ConfigMetadata config = entry.getFileMetadata().getConfigMetadata();
-
-                // getting package/class list from Test Module Configuration
-                mTestClassList = new ArrayList<String>();
-                mTestApkList = new ArrayList<String>();
-                mHostTestJarList = new ArrayList<String>();
-                List<Option> optList;
-                List<ConfigMetadata.TestClass> testClassesList = config.getTestClassesList();
-                for (ConfigMetadata.TestClass tClass : testClassesList) {
-                    boolean isHostTest = false;
-                    boolean isAndroidJunitTest = false;
-                    optList = tClass.getOptionsList();
-                    if (HOST_TEST_CLASS_TAG.equals(tClass.getTestClass())) {
-                        isHostTest = true;
-                        pType = TestSuite.Package.Type.JAVAHOST;
-                    } else if (ANDROID_JUNIT_TEST_TAG.equals(tClass.getTestClass())) {
-                        isAndroidJunitTest = true;
-                    } else if (GTEST_TAG.equals(tClass.getTestClass())) {
-                        pType = TestSuite.Package.Type.GTEST;
-                    } else if (DEQP_TEST_TAG.equals(tClass.getTestClass())) {
-                        pType = TestSuite.Package.Type.DEQP;
-                    } else if (LIBCORE_TEST_TAG.equals(tClass.getTestClass())) {
-                        pType = TestSuite.Package.Type.LIBCORE;
-                    } else if (DALVIK_TEST_TAG.equals(tClass.getTestClass())) {
-                        // cts/tests/jdwp/AndroidTest.xml
-                        pType = TestSuite.Package.Type.DALVIK;
-                    } else {
-                        System.err.printf(
-                                "Unknown Test Type: %s %s\n",
-                                entry.getName(), tClass.getTestClass());
-                    }
-
-                    for (Option opt : optList) {
-                        if (isAndroidJunitTest && PACKAGE_TAG.equalsIgnoreCase(opt.getName())) {
-                            mTestClassList.add(opt.getValue());
-                        } else if (isHostTest && JAR_TAG.equalsIgnoreCase(opt.getName())) {
-                            mHostTestJarList.add(opt.getValue());
-                        }
-                    }
-                }
-
-                // getting apk list from Test Module Configuration
-                List<ConfigMetadata.TargetPreparer> tPrepList = config.getTargetPreparersList();
-                for (ConfigMetadata.TargetPreparer tPrep : tPrepList) {
-                    optList = tPrep.getOptionsList();
-                    for (Option opt : optList) {
-                        if (TEST_FILE_NAME_TAG.equalsIgnoreCase(opt.getName())) {
-                            mTestApkList.add(opt.getValue());
-                        }
-                    }
-                }
-
-                TestSuite.Package.Builder tsPkgBuilder;
-                if (pType == TestSuite.Package.Type.JAVAHOST) {
-                    tsPkgBuilder = parseJarTestCase();
-                } else {
-                    tsPkgBuilder = parseApkTestCase();
-                }
-
-                tsPkgBuilder.setName(entry.getName().replaceAll(CONFIG_REGEX, ""));
-                if (null != pType) {
-                    tsPkgBuilder.setType(pType);
-                }
-
-                tsBuilder.addPackages(tsPkgBuilder);
+                TestModuleConfig config = entry.getTestModuleConfig();
+                TestSuite.Module.Builder moduleBuilder = praseModule(config);
+                moduleBuilder.setConfigFile(entry.getRelativePath());
+                tsBuilder.addModules(moduleBuilder);
             }
         }
         return tsBuilder;
     }
 
-    // Get test case list from an APK
-    private TestSuite.Package.Builder parseApkTestCase() {
-        TestSuite.Package.Builder tsPkgBuilder = TestSuite.Package.newBuilder();
-        for (String apkName : mTestApkList) {
-            DexFile dexFile = null;
-            String apkPath = Paths.get(mFolderPath, TESTCASES_FOLDER_TAG, apkName).toString();
-            try {
-                dexFile = DexFileFactory.loadDexFile(apkPath, Opcodes.forApi(OPCODE_API));
-            } catch (IOException | DexFileFactory.DexFileNotFoundException ex) {
-                System.err.println("Unable to load dex file: " + apkPath);
-                // ex.printStackTrace();
-                continue;
+    private TestSuite.Module.Builder praseModule(TestModuleConfig config) {
+        TestSuite.Module.Builder moduleBuilder = TestSuite.Module.newBuilder();
+        // parse test package and class
+        List<TestModuleConfig.TestClass> testClassesList = config.getTestClassesList();
+        moduleBuilder.setName(config.getModuleName());
+        for (TestModuleConfig.TestClass tClass : testClassesList) {
+            String testClass = tClass.getTestClass();
+            moduleBuilder.setTestClass(testClass);
+            switch (testClass) {
+                case ANDROID_JUNIT_TEST_TAG:
+                    moduleBuilder.setTestType(TestSuite.TestType.ANDROIDJUNIT);
+                    parseAndroidJUnitTest(moduleBuilder, config, tClass.getTestClass());
+                    break;
+                case HOST_TEST_CLASS_TAG:
+                    moduleBuilder.setTestType(TestSuite.TestType.JAVAHOST);
+                    parseJavaHostTest(moduleBuilder, config, tClass.getTestClass());
+                    break;
+                default:
+                    //ToDo
+                    moduleBuilder.setTestType(TestSuite.TestType.UNKNOWN);
+                    TestSuite.Module.Package.Builder pkgBuilder =
+                            TestSuite.Module.Package.newBuilder();
+                    moduleBuilder.addPackages(pkgBuilder);
+                    System.err.printf(
+                            "ToDo Test Type: %s %s\n", tClass.getTestClass(), tClass.getPackage());
             }
+        }
+        return moduleBuilder;
+    }
 
-            tsPkgBuilder.setName(apkName);
+    private void parseAndroidJUnitTest(
+            TestSuite.Module.Builder moduleBuilder, TestModuleConfig config, String tClass) {
+        // getting apk list from Test Module Configuration
+        List<TestModuleConfig.TargetPreparer> tPrepList = config.getTargetPreparersList();
+        for (TestModuleConfig.TargetPreparer tPrep : tPrepList) {
+            for (Option opt : tPrep.getOptionsList()) {
+                if (TEST_FILE_NAME_TAG.equalsIgnoreCase(opt.getName())) {
+                    TestSuite.Module.Package.Builder pkgBuilder =
+                            TestSuite.Module.Package.newBuilder();
+                    String testFileName = opt.getValue();
+                    Entry tEntry = getFileEntry(testFileName);
+                    pkgBuilder.setName(testFileName);
+                    pkgBuilder.setPackageFile(tEntry.getRelativePath());
+                    pkgBuilder.setContentId(tEntry.getContentId());
+                    parseApkTestCase(pkgBuilder, config);
+                    moduleBuilder.addPackages(pkgBuilder);
+                }
+            }
+        }
+    }
+
+    private Entry getFileEntry(String name) {
+        Entry fEntry = null;
+        for (Entry et : mRelContent.getFileEntriesList()) {
+            if (name.equals(et.getName())) {
+                fEntry = et;
+                break;
+            }
+        }
+        return fEntry;
+    }
+    // Parses test case list from an APK
+    private void parseApkTestCase(
+            TestSuite.Module.Package.Builder pkgBuilder, TestModuleConfig config) {
+        DexFile dexFile = null;
+        String apkPath = Paths.get(mFolderPath, pkgBuilder.getPackageFile()).toString();
+        String moduleName = config.getModuleName();
+
+        // Loads a Dex file
+        try {
+            dexFile = DexFileFactory.loadDexFile(apkPath, Opcodes.forApi(mApiLevel));
+
+            // Iterates through all clesses in the Dex file
             for (ClassDef classDef : dexFile.getClasses()) {
                 // adjust the format Lclass/y;
                 String className = classDef.getType().replace('/', '.');
@@ -223,105 +221,138 @@
                     className = className.substring(1, className.length() - 1);
                 }
 
-                TestSuite.Package.Class.ClassType cType;
-                cType = chkTestType(classDef);
-                if (TestSuite.Package.Class.ClassType.JUNIT3 == cType) {
-                    TestSuite.Package.Class.Builder tClassBuilder =
-                            TestSuite.Package.Class.newBuilder();
-                    tClassBuilder.setClassType(cType);
-                    tClassBuilder.setApk(apkName);
-                    tClassBuilder.setName(className);
-
-                    for (Method method : classDef.getMethods()) {
-                        if ((method.getAccessFlags() & AccessFlags.PUBLIC.getValue()) != 0) {
-                            String mName = method.getName();
-                            if (hasAnnotationSuffix(
-                                    method.getAnnotations(), SUPPRESS_ANNOTATION_TAG)) {
-                                System.err.printf("%s#%s with Suppress:\n", className, mName);
-                                System.err.println(method.getAnnotations());
-                            } else if (mName.startsWith(TEST_PREFIX_TAG)) {
-                                TestSuite.Package.Class.Method.Builder methodBuilder =
-                                        TestSuite.Package.Class.Method.newBuilder();
+                // Parses test classes
+                TestClassType cType;
+                cType = chkTestClassType(classDef);
+                TestSuite.Module.Package.Class.Builder tClassBuilder =
+                        TestSuite.Module.Package.Class.newBuilder();
+                switch (cType) {
+                    case JUNIT3:
+                        tClassBuilder.setTestClassType(cType);
+                        tClassBuilder.setName(className);
+                        // Checks all test method
+                        for (Method method : classDef.getMethods()) {
+                            // Only care about Public
+                            if ((method.getAccessFlags() & AccessFlags.PUBLIC.getValue()) != 0) {
+                                String mName = method.getName();
+                                // Warn current test result accounting does not work well with Supress
+                                if (hasAnnotationSuffix(
+                                        method.getAnnotations(), SUPPRESS_ANNOTATION_TAG)) {
+                                    System.err.printf("%s#%s with Suppress:\n", className, mName);
+                                    System.err.println(method.getAnnotations());
+                                } else if (mName.startsWith(TEST_PREFIX_TAG)) {
+                                    // Junit3 style test case name starts with test
+                                    TestSuite.Module.Package.Class.Method.Builder methodBuilder =
+                                            TestSuite.Module.Package.Class.Method.newBuilder();
+                                    methodBuilder.setName(mName);
+                                    // Check if it's an known failure
+                                    String nfFilter =
+                                            getKnownFailureFilter(moduleName, className, mName);
+                                    if (null != nfFilter) {
+                                        methodBuilder.setKnownFailureFilter(nfFilter);
+                                    }
+                                    tClassBuilder.addMethods(methodBuilder);
+                                }
+                            }
+                        }
+                        pkgBuilder.addClasses(tClassBuilder);
+                        break;
+                    case JUNIT4:
+                        tClassBuilder.setTestClassType(cType);
+                        tClassBuilder.setName(className);
+                        for (Method method : classDef.getMethods()) {
+                            // Junit4 style test case annotated with @Test
+                            if (hasAnnotation(method.getAnnotations(), TEST_ANNOTATION_TAG)) {
+                                String mName = method.getName();
+                                TestSuite.Module.Package.Class.Method.Builder methodBuilder =
+                                        TestSuite.Module.Package.Class.Method.newBuilder();
                                 methodBuilder.setName(mName);
+                                // Check if it's an known failure
+                                String nfFilter =
+                                        getKnownFailureFilter(moduleName, className, mName);
+                                if (null != nfFilter) {
+                                    methodBuilder.setKnownFailureFilter(nfFilter);
+                                }
                                 tClassBuilder.addMethods(methodBuilder);
                             }
                         }
-                    }
-                    tsPkgBuilder.addClasses(tClassBuilder);
-                } else if (TestSuite.Package.Class.ClassType.JUNIT4 == cType) {
-                    TestSuite.Package.Class.Builder tClassBuilder =
-                            TestSuite.Package.Class.newBuilder();
-                    tClassBuilder.setClassType(cType);
-                    tClassBuilder.setApk(apkName);
-                    tClassBuilder.setName(className);
-
-                    for (Method method : classDef.getMethods()) {
-                        if (hasAnnotation(method.getAnnotations(), TEST_ANNOTATION_TAG)) {
-                            String mName = method.getName();
-                            TestSuite.Package.Class.Method.Builder methodBuilder =
-                                    TestSuite.Package.Class.Method.newBuilder();
-                            methodBuilder.setName(mName);
-                            tClassBuilder.addMethods(methodBuilder);
+                        pkgBuilder.addClasses(tClassBuilder);
+                        break;
+                    case PARAMETERIZED:
+                        // ToDo WIP
+                        tClassBuilder.setTestClassType(cType);
+                        tClassBuilder.setName(className);
+                        for (Method method : classDef.getMethods()) {
+                            if (hasAnnotation(method.getAnnotations(), TEST_ANNOTATION_TAG)) {
+                                String mName = method.getName();
+                                TestSuite.Module.Package.Class.Method.Builder methodBuilder =
+                                        TestSuite.Module.Package.Class.Method.newBuilder();
+                                methodBuilder.setName(mName);
+                                // Check if it's an known failure
+                                String nfFilter =
+                                        getKnownFailureFilter(moduleName, className, mName);
+                                if (null != nfFilter) {
+                                    methodBuilder.setKnownFailureFilter(nfFilter);
+                                }
+                                tClassBuilder.addMethods(methodBuilder);
+                            }
                         }
-                    }
-                    tsPkgBuilder.addClasses(tClassBuilder);
-                } else if (TestSuite.Package.Class.ClassType.PARAMETERIZED == cType) {
-                    TestSuite.Package.Class.Builder tClassBuilder =
-                            TestSuite.Package.Class.newBuilder();
-                    tClassBuilder.setClassType(cType);
-                    tClassBuilder.setApk(apkName);
-                    tClassBuilder.setName(className);
-
-                    for (Method method : classDef.getMethods()) {
-                        if (hasAnnotation(method.getAnnotations(), TEST_ANNOTATION_TAG)) {
-                            String mName = method.getName();
-                            TestSuite.Package.Class.Method.Builder methodBuilder =
-                                    TestSuite.Package.Class.Method.newBuilder();
-                            methodBuilder.setName(mName);
-                            tClassBuilder.addMethods(methodBuilder);
-                        }
-                    }
-                    tsPkgBuilder.addClasses(tClassBuilder);
+                        pkgBuilder.addClasses(tClassBuilder);
+                        break;
+                    default:
+                        // Not a known test class
                 }
             }
+        } catch (IOException | DexFileFactory.DexFileNotFoundException ex) {
+            System.err.println("Unable to load dex file: " + apkPath);
+            // ex.printStackTrace();
         }
-        return tsPkgBuilder;
     }
 
-    private TestSuite.Package.Builder parseJarTestCase() {
-        TestSuite.Package.Builder tsPkgBuilder = TestSuite.Package.newBuilder();
-        for (String jarName : mHostTestJarList) {
-            tsPkgBuilder.setName(jarName);
+    private void parseJavaHostTest(
+            TestSuite.Module.Builder moduleBuilder, TestModuleConfig config, String tClass) {
+        TestSuite.Module.Package.Builder pkgBuilder = TestSuite.Module.Package.newBuilder();
+        //Assuming there is only one test Jar
+        String testFileName = config.getTestJars(0);
+        Entry tEntry = getFileEntry(testFileName);
+        String jarPath = tEntry.getRelativePath();
 
-            // Includes [x]-tradefed.jar for classes such as CompatibilityHostTestBase
-            Collection<Class<?>> classes =
-                    getJarTestClasses(
-                            Paths.get(mFolderPath, TESTCASES_FOLDER_TAG, jarName).toFile(),
-                            Paths.get(mFolderPath, mRelContent.getTestSuiteTradefed()).toFile());
-            for (Class<?> c : classes) {
-                TestSuite.Package.Class.Builder tClassBuilder =
-                        TestSuite.Package.Class.newBuilder();
-                tClassBuilder.setClassType(TestSuite.Package.Class.ClassType.JAVAHOST);
-                tClassBuilder.setApk(jarName);
-                tClassBuilder.setName(c.getName());
+        pkgBuilder.setName(testFileName);
+        pkgBuilder.setPackageFile(jarPath);
+        pkgBuilder.setContentId(tEntry.getContentId());
+        Collection<Class<?>> classes =
+                getJarTestClasses(
+                        Paths.get(mFolderPath, jarPath).toFile(),
+                        // Includes [x]-tradefed.jar for classes such as CompatibilityHostTestBase
+                        Paths.get(mFolderPath, mRelContent.getTestSuiteTradefed()).toFile());
 
-                System.err.printf("class: %s\n", c.getName());
-                for (java.lang.reflect.Method m : c.getMethods()) {
-                    int mdf = m.getModifiers();
-                    if (Modifier.isPublic(mdf) || Modifier.isProtected(mdf)) {
-                        if (m.getName().startsWith(TEST_PREFIX_TAG)) {
-                            System.err.printf("test: %s\n", m.getName());
-                            TestSuite.Package.Class.Method.Builder methodBuilder =
-                                    TestSuite.Package.Class.Method.newBuilder();
-                            methodBuilder.setName(m.getName());
-                            tClassBuilder.addMethods(methodBuilder);
+        for (Class<?> c : classes) {
+            TestSuite.Module.Package.Class.Builder tClassBuilder =
+                    TestSuite.Module.Package.Class.newBuilder();
+            tClassBuilder.setTestClassType(TestClassType.JAVAHOST);
+            tClassBuilder.setName(c.getName());
+
+            for (java.lang.reflect.Method m : c.getMethods()) {
+                int mdf = m.getModifiers();
+                if (Modifier.isPublic(mdf) || Modifier.isProtected(mdf)) {
+                    if (m.getName().startsWith(TEST_PREFIX_TAG)) {
+                        TestSuite.Module.Package.Class.Method.Builder methodBuilder =
+                                TestSuite.Module.Package.Class.Method.newBuilder();
+                        methodBuilder.setName(m.getName());
+                        // Check if it's an known failure
+                        String nfFilter =
+                                getKnownFailureFilter(
+                                        config.getModuleName(), c.getName(), m.getName());
+                        if (null != nfFilter) {
+                            methodBuilder.setKnownFailureFilter(nfFilter);
                         }
+                        tClassBuilder.addMethods(methodBuilder);
                     }
                 }
-                tsPkgBuilder.addClasses(tClassBuilder);
             }
+            pkgBuilder.addClasses(tClassBuilder);
         }
-        return tsPkgBuilder;
+        moduleBuilder.addPackages(pkgBuilder);
     }
 
     private static boolean hasAnnotation(Set<? extends Annotation> annotations, String tag) {
@@ -342,33 +373,33 @@
         return false;
     }
 
-    private static TestSuite.Package.Class.ClassType chkTestType(ClassDef classDef) {
+    private static TestClassType chkTestClassType(ClassDef classDef) {
         // Only care about Public Class
         if ((classDef.getAccessFlags() & AccessFlags.PUBLIC.getValue()) == 0) {
-            return TestSuite.Package.Class.ClassType.UNKNOWN;
+            return TestClassType.UNKNOWN;
         }
 
         for (Annotation annotation : classDef.getAnnotations()) {
             if (annotation.getType().equals(DEPRECATED_ANNOTATION_TAG)) {
-                return TestSuite.Package.Class.ClassType.UNKNOWN;
+                return TestClassType.UNKNOWN;
             }
             if (annotation.getType().equals(RUN_WITH_ANNOTATION_TAG)) {
                 for (AnnotationElement annotationEle : annotation.getElements()) {
                     String aName = annotationEle.getName();
                     if (aName.equals(ANDROID_JUNIT4_TEST_TAG)) {
-                        return TestSuite.Package.Class.ClassType.JUNIT4;
+                        return TestClassType.JUNIT4;
                     } else if (aName.equals(PARAMETERIZED_TAG)) {
-                        return TestSuite.Package.Class.ClassType.PARAMETERIZED;
+                        return TestClassType.PARAMETERIZED;
                     }
                 }
-                return TestSuite.Package.Class.ClassType.JUNIT4;
+                return TestClassType.JUNIT4;
             }
         }
 
         if (classDef.getType().endsWith(TEST_TAG) || classDef.getType().endsWith(TESTS_TAG)) {
-            return TestSuite.Package.Class.ClassType.JUNIT3;
+            return TestClassType.JUNIT3;
         } else {
-            return TestSuite.Package.Class.ClassType.UNKNOWN;
+            return TestClassType.UNKNOWN;
         }
     }
 
@@ -455,42 +486,39 @@
         return name.substring(0, name.length() - 6).replace('/', '.');
     }
 
-    private static boolean isKnownFailure(String tsName, List<String> knownFailures) {
+    private String getKnownFailureFilter(String tModule, String tClass, String tMethod) {
+        List<String> knownFailures = mRelContent.getKnownFailuresList();
+        String tsName = String.format(TESTCASE_NAME_FORMAT, tModule, tClass, tMethod);
         for (String kf : knownFailures) {
             if (tsName.startsWith(kf)) {
-                return true;
+                return kf;
             }
         }
-        return false;
+        return null;
     }
 
     // Iterates though all test suite content and prints them.
-    public void writeCsvFile(String csvFile) {
+    public void writeCsvFile(String relNameVer, String csvFile) {
         TestSuite ts = getTestSuite();
-        List<String> knownFailures = mRelContent.getKnownFailuresList();
         try {
             FileWriter fWriter = new FileWriter(csvFile);
             PrintWriter pWriter = new PrintWriter(fWriter);
             //Header
-            pWriter.println("Module,Class,Test,Apk,Type");
-            for (TestSuite.Package pkg : ts.getPackagesList()) {
-                for (TestSuite.Package.Class cls : pkg.getClassesList()) {
-                    for (TestSuite.Package.Class.Method mtd : cls.getMethodsList()) {
-                        String testCaseName =
-                                String.format(
-                                        TESTCASE_NAME_FORMAT,
-                                        pkg.getName(),
-                                        cls.getName(),
-                                        mtd.getName());
-                        // Filter out known failures
-                        if (!isKnownFailure(testCaseName, knownFailures)) {
+            pWriter.println(
+                    "release,module,test_class,test,test_package,test_type,known_failure_filter");
+            for (TestSuite.Module module : ts.getModulesList()) {
+                for (TestSuite.Module.Package pkg : module.getPackagesList()) {
+                    for (TestSuite.Module.Package.Class cls : pkg.getClassesList()) {
+                        for (TestSuite.Module.Package.Class.Method mtd : cls.getMethodsList()) {
                             pWriter.printf(
-                                    "%s,%s,%s,%s,%s\n",
-                                    pkg.getName(),
+                                    "%s,%s,%s,%s,%s,%s,%s\n",
+                                    relNameVer,
+                                    module.getName(),
                                     cls.getName(),
                                     mtd.getName(),
-                                    cls.getApk(),
-                                    cls.getClassType());
+                                    pkg.getPackageFile(),
+                                    cls.getTestClassType(),
+                                    mtd.getKnownFailureFilter());
                         }
                     }
                 }
@@ -503,35 +531,42 @@
     }
 
     // Iterates though all test suite content and prints them.
-    public void writeSummaryCsvFile(String csvFile) {
+    public void writeSummaryCsvFile(String relNameVer, String csvFile) {
         TestSuite ts = getTestSuite();
-        List<String> knownFailures = mRelContent.getKnownFailuresList();
         try {
             FileWriter fWriter = new FileWriter(csvFile);
             PrintWriter pWriter = new PrintWriter(fWriter);
 
             //Header
-            pWriter.print("Module,Test#,Type,Class#\n");
+            pWriter.print(
+                    "release,module,test_no,known_failure_no,test_type,test_class,test_config_file\n");
 
-            for (TestSuite.Package pkg : ts.getPackagesList()) {
+            for (TestSuite.Module module : ts.getModulesList()) {
                 int classCnt = 0;
                 int methodCnt = 0;
-                for (TestSuite.Package.Class cls : pkg.getClassesList()) {
-                    for (TestSuite.Package.Class.Method mtd : cls.getMethodsList()) {
-                        String testCaseName =
-                                String.format(
-                                        TESTCASE_NAME_FORMAT,
-                                        pkg.getName(),
-                                        cls.getName(),
-                                        mtd.getName());
-                        // Filter out known failures
-                        if (!isKnownFailure(testCaseName, knownFailures)) {
-                            methodCnt++;
+                int kfCnt = 0;
+                for (TestSuite.Module.Package pkg : module.getPackagesList()) {
+                    for (TestSuite.Module.Package.Class cls : pkg.getClassesList()) {
+                        for (TestSuite.Module.Package.Class.Method mtd : cls.getMethodsList()) {
+                            // Filter out known failures
+                            if (mtd.getKnownFailureFilter().isEmpty()) {
+                                methodCnt++;
+                            } else {
+                                kfCnt++;
+                            }
                         }
+                        classCnt++;
                     }
-                    classCnt++;
                 }
-                pWriter.printf("%s,%s,%s,%d\n", pkg.getName(), methodCnt, pkg.getType(), classCnt);
+                pWriter.printf(
+                        "%s,%s,%d,%d,%s,%s,%s\n",
+                        relNameVer,
+                        module.getName(),
+                        methodCnt,
+                        kfCnt,
+                        module.getTestType(),
+                        module.getTestClass(),
+                        module.getConfigFile());
             }
             pWriter.flush();
             pWriter.close();