Add --dump-all-members option to class2greylist.

This is being used to generate a whitelist.txt for old versions of the tree
where the current build rules don't exists.

Bug: 113506167
Test: out/host/linux-x86/bin/class2greylist -m out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes.jar
Change-Id: I317b7227d77fc1bc4c9a8b1fa7a6493e127938ab
diff --git a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
index 694a5f4..9262076 100644
--- a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
+++ b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
@@ -86,6 +86,12 @@
                 .withDescription("Enable debug")
                 .create("d"));
         options.addOption(OptionBuilder
+                .withLongOpt("dump-all-members")
+                .withDescription("Dump all members from jar files to stdout. Ignore annotations. " +
+                        "Do not use in conjunction with any other arguments.")
+                .hasArgs(0)
+                .create('m'));
+        options.addOption(OptionBuilder
                 .withLongOpt("help")
                 .hasArgs(0)
                 .withDescription("Show this help")
@@ -113,16 +119,21 @@
         }
 
         Status status = new Status(cmd.hasOption('d'));
-        try {
-            Class2Greylist c2gl = new Class2Greylist(
-                    status,
-                    cmd.getOptionValue('p', null),
-                    cmd.getOptionValues('g'),
-                    cmd.getOptionValue('w', null),
-                    jarFiles);
-            c2gl.main();
-        } catch (IOException e) {
-            status.error(e);
+
+        if (cmd.hasOption('m')) {
+            dumpAllMembers(status, jarFiles);
+        } else {
+            try {
+                Class2Greylist c2gl = new Class2Greylist(
+                        status,
+                        cmd.getOptionValue('p', null),
+                        cmd.getOptionValues('g'),
+                        cmd.getOptionValue('w', null),
+                        jarFiles);
+                c2gl.main();
+            } catch (IOException e) {
+                status.error(e);
+            }
         }
 
         if (status.ok()) {
@@ -221,6 +232,20 @@
         return map;
     }
 
+    private static void dumpAllMembers(Status status, String[] jarFiles) {
+        for (String jarFile : jarFiles) {
+            status.debug("Processing jar file %s", jarFile);
+            try {
+                JarReader reader = new JarReader(status, jarFile);
+                reader.stream().forEach(clazz -> new MemberDumpingVisitor(clazz, status)
+                        .visit());
+                reader.close();
+            } catch (IOException e) {
+                status.error(e);
+            }
+        }
+    }
+
     private static void help(Options options) {
         new HelpFormatter().printHelp(
                 "class2greylist path/to/classes.jar [classes2.jar ...]",
diff --git a/tools/class2greylist/src/com/android/class2greylist/MemberDumpingVisitor.java b/tools/class2greylist/src/com/android/class2greylist/MemberDumpingVisitor.java
new file mode 100644
index 0000000..6677a3f
--- /dev/null
+++ b/tools/class2greylist/src/com/android/class2greylist/MemberDumpingVisitor.java
@@ -0,0 +1,47 @@
+package com.android.class2greylist;
+
+import org.apache.bcel.classfile.DescendingVisitor;
+import org.apache.bcel.classfile.EmptyVisitor;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.FieldOrMethod;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+
+/**
+ * A class file visitor that simply prints to stdout the signature of every member within the class.
+ */
+public class MemberDumpingVisitor extends EmptyVisitor {
+
+    private final Status mStatus;
+    private final DescendingVisitor mDescendingVisitor;
+
+    /**
+     * Creates a visitor for a class.
+     *
+     * @param clazz Class to visit
+     */
+    public MemberDumpingVisitor(JavaClass clazz, Status status) {
+        mStatus = status;
+        mDescendingVisitor = new DescendingVisitor(clazz, this);
+    }
+
+    public void visit() {
+        mDescendingVisitor.visit();
+    }
+
+    @Override
+    public void visitMethod(Method method) {
+        visitMember(method, "L%s;->%s%s");
+    }
+
+    @Override
+    public void visitField(Field field) {
+        visitMember(field, "L%s;->%s:%s");
+    }
+
+    private void visitMember(FieldOrMethod member, String signatureFormatString) {
+        AnnotationContext context = new AnnotationContext(mStatus, member,
+                (JavaClass) mDescendingVisitor.predecessor(), signatureFormatString);
+        System.out.println(context.getMemberDescriptor());
+    }
+}