From b82fbc64428754818e1e6178f5096c83c7f8f252 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 3 Feb 2011 22:56:14 -0800 Subject: [PATCH] merge "SDK: make 'mkstub' less verbose." from HC. Do not merge. mkstub is the tool used to stub the google_apis maps.jar. Since we're integrating it in the build, we want to control its verbosity. Change-Id: I93d7dc6a63426affac008f8ef367a0d79277b59a --- .../src/com/android/mkstubs/AsmAnalyzer.java | 15 +- .../android/mkstubs/FilterClassAdapter.java | 12 +- .../mkstubs/src/com/android/mkstubs/Main.java | 144 ++++++++++++++---- .../com/android/mkstubs/SourceGenerator.java | 25 +-- .../com/android/mkstubs/StubGenerator.java | 25 +-- .../android/mkstubs/SourceGeneratorTest.java | 12 +- 6 files changed, 168 insertions(+), 65 deletions(-) diff --git a/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java b/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java index 5e64ae6c4..0b73dc516 100644 --- a/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java +++ b/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java @@ -16,6 +16,8 @@ package com.android.mkstubs; +import com.android.mkstubs.Main.Logger; + import org.objectweb.asm.ClassReader; import java.io.IOException; @@ -53,7 +55,7 @@ class AsmAnalyzer { classes.put(className, cr); } } - + return classes; } @@ -72,25 +74,26 @@ class AsmAnalyzer { /** * Filters the set of classes. Removes all classes that should not be included in the * filter or that should be excluded. This modifies the map in-place. - * + * * @param classes The in-out map of classes to examine and filter. The map is filtered * in-place. * @param filter A filter describing which classes to include and which ones to exclude. + * @param log */ - void filter(Map classes, Filter filter) { + void filter(Map classes, Filter filter, Logger log) { Set keys = classes.keySet(); for(Iterator it = keys.iterator(); it.hasNext(); ) { String key = it.next(); // TODO: We *could* filter out all private classes here: classes.get(key).getAccess(). - + // remove if we don't keep it if (!filter.accept(key)) { - System.out.println("- Remove class " + key); + log.debug("- Remove class " + key); it.remove(); } } } - + } diff --git a/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java b/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java index 3874e6b50..6f570c70b 100644 --- a/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java +++ b/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java @@ -16,6 +16,8 @@ package com.android.mkstubs; +import com.android.mkstubs.Main.Logger; + import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassAdapter; @@ -30,12 +32,14 @@ import org.objectweb.asm.Opcodes; */ class FilterClassAdapter extends ClassAdapter { + private final Logger mLog; private final Filter mFilter; private String mClassName; - public FilterClassAdapter(ClassVisitor writer, Filter filter) { + public FilterClassAdapter(ClassVisitor writer, Filter filter, Logger log) { super(writer); mFilter = filter; + mLog = log; } @Override @@ -73,7 +77,7 @@ class FilterClassAdapter extends ClassAdapter { String filterName = String.format("%s#%s", mClassName, name); if (!mFilter.accept(filterName)) { - System.out.println("- Remove field " + filterName); + mLog.debug("- Remove field " + filterName); return null; } @@ -105,7 +109,7 @@ class FilterClassAdapter extends ClassAdapter { String filterName = String.format("%s#%s%s", mClassName, name, desc); if (!mFilter.accept(filterName)) { - System.out.println("- Remove method " + filterName); + mLog.debug("- Remove method " + filterName); return null; } @@ -114,7 +118,7 @@ class FilterClassAdapter extends ClassAdapter { filterName = String.format("%s#%s%s", mClassName, name, signature); if (!mFilter.accept(filterName)) { - System.out.println("- Remove method " + filterName); + mLog.debug("- Remove method " + filterName); return null; } } diff --git a/tools/mkstubs/src/com/android/mkstubs/Main.java b/tools/mkstubs/src/com/android/mkstubs/Main.java index 55f949968..927ff9e10 100644 --- a/tools/mkstubs/src/com/android/mkstubs/Main.java +++ b/tools/mkstubs/src/com/android/mkstubs/Main.java @@ -16,6 +16,8 @@ package com.android.mkstubs; +import com.android.mkstubs.Main.Params; + import org.objectweb.asm.ClassReader; import java.io.BufferedReader; @@ -31,7 +33,7 @@ import java.util.Map; * For workflow details, see {@link #process(Params)}. */ public class Main { - + /** * A struct-like class to hold the various input values (e.g. command-line args) */ @@ -39,13 +41,23 @@ public class Main { private String mInputJarPath; private String mOutputJarPath; private Filter mFilter; - - public Params(String inputJarPath, String outputJarPath) { - mInputJarPath = inputJarPath; - mOutputJarPath = outputJarPath; + private boolean mVerbose; + private boolean mDumpSource; + + public Params() { mFilter = new Filter(); } + /** Sets the name of the input jar, where to read classes from. Must not be null. */ + public void setInputJarPath(String inputJarPath) { + mInputJarPath = inputJarPath; + } + + /** Sets the name of the output jar, where to write classes to. Must not be null. */ + public void setOutputJarPath(String outputJarPath) { + mOutputJarPath = outputJarPath; + } + /** Returns the name of the input jar, where to read classes from. */ public String getInputJarPath() { return mInputJarPath; @@ -60,13 +72,53 @@ public class Main { public Filter getFilter() { return mFilter; } + + /** Sets verbose mode on. Default is off. */ + public void setVerbose() { + mVerbose = true; + } + + /** Returns true if verbose mode is on. */ + public boolean isVerbose() { + return mVerbose; + } + + /** Sets dump source mode on. Default is off. */ + public void setDumpSource() { + mDumpSource = true; + } + + /** Returns true if source should be dumped. */ + public boolean isDumpSource() { + return mDumpSource; + } } - + + /** Logger that writes on stdout depending a conditional verbose mode. */ + static class Logger { + private final boolean mVerbose; + + public Logger(boolean verbose) { + mVerbose = verbose; + } + + /** Writes to stdout only in verbose mode. */ + public void debug(String msg, Object...params) { + if (mVerbose) { + System.out.println(String.format(msg, params)); + } + } + + /** Writes to stdout all the time. */ + public void info(String msg, Object...params) { + System.out.println(String.format(msg, params)); + } + } + /** * Main entry point. Processes arguments then performs the "real" work. */ public static void main(String[] args) { - Main m = new Main(); try { Params p = m.processArgs(args); @@ -88,17 +140,32 @@ public class Main { * @throws IOException on failure to read a pattern file. */ private Params processArgs(String[] args) throws IOException { - - if (args.length < 2) { - usage(); + Params p = new Params(); + + for (String arg : args) { + if (arg.startsWith("--")) { + if (arg.startsWith("--v")) { + p.setVerbose(); + } else if (arg.startsWith("--s")) { + p.setDumpSource(); + } else if (arg.startsWith("--h")) { + usage(null); + } else { + usage("Unknown argument: " + arg); + } + } else if (p.getInputJarPath() == null) { + p.setInputJarPath(arg); + } else if (p.getOutputJarPath() == null) { + p.setOutputJarPath(arg); + } else { + addString(p, arg); + } } - Params p = new Params(args[0], args[1]); - - for (int i = 2; i < args.length; i++) { - addString(p, args[i]); + if (p.getInputJarPath() == null && p.getOutputJarPath() == null) { + usage("Missing input or output JAR."); } - + return p; } @@ -112,7 +179,7 @@ public class Main { * * The input string is trimmed so any space around the first letter (-/+/@) or * at the end is removed. Empty strings are ignored. - * + * * @param p The params which filters to edit. * @param s The string to examine. * @throws IOException @@ -127,13 +194,13 @@ public class Main { if (s.length() < 2) { return; } - + char mode = s.charAt(0); s = s.substring(1).trim(); if (mode == '@') { addStringsFromFile(p, s); - + } else if (mode == '-') { s = s.replace('.', '/'); // transform FQCN into ASM internal name if (s.endsWith("*")) { @@ -154,11 +221,11 @@ public class Main { /** * Adds all the filter strings from the given file. - * + * * @param p The params which filter to edit. * @param osFilePath The OS path to the file containing the patterns. * @throws IOException - * + * * @see #addString(Params, String) */ private void addStringsFromFile(Params p, String osFilePath) @@ -179,9 +246,19 @@ public class Main { /** * Prints some help to stdout. + * @param error The error that generated the usage, if any. Can be null. */ - private void usage() { - System.out.println("Usage: mkstub input.jar output.jar [excluded-class @excluded-classes-file ...]"); + private void usage(String error) { + if (error != null) { + System.out.println("ERROR: " + error); + } + + System.out.println("Usage: mkstub [--h|--s|--v] input.jar output.jar [excluded-class @excluded-classes-file ...]"); + + System.out.println("Options:\n" + + " --h | --help : print this usage.\n" + + " --v | --verbose : verbose mode.\n" + + " --s | --source : dump source equivalent to modified byte code.\n\n"); System.out.println("Include syntax:\n" + "+com.package.* : whole package, with glob\n" + @@ -193,6 +270,7 @@ public class Main { "-com.package.Class[$Inner] or ...Class*: whole classes with optional glob\n" + "-com.package.Class#method: whole method or field\n" + "-com.package.Class#method(IILjava/lang/String;)V: specific method with signature.\n\n"); + System.exit(1); } @@ -211,20 +289,22 @@ public class Main { AsmAnalyzer aa = new AsmAnalyzer(); Map classes = aa.parseInputJar(p.getInputJarPath()); - System.out.println(String.format("Classes loaded: %d", classes.size())); - - aa.filter(classes, p.getFilter()); + Logger log = new Logger(p.isVerbose()); + log.info("Classes loaded: %d", classes.size()); - System.out.println(String.format("Classes filtered: %d", classes.size())); + aa.filter(classes, p.getFilter(), log); + log.info("Classes filtered: %d", classes.size()); // dump as Java source files, mostly for debugging - SourceGenerator src_gen = new SourceGenerator(); - File dst_src_dir = new File(p.getOutputJarPath() + "_sources"); - dst_src_dir.mkdir(); - src_gen.generateSource(dst_src_dir, classes, p.getFilter()); - + if (p.isDumpSource()) { + SourceGenerator src_gen = new SourceGenerator(log); + File dst_src_dir = new File(p.getOutputJarPath() + "_sources"); + dst_src_dir.mkdir(); + src_gen.generateSource(dst_src_dir, classes, p.getFilter()); + } + // dump the stubbed jar - StubGenerator stub_gen = new StubGenerator(); + StubGenerator stub_gen = new StubGenerator(log); File dst_jar = new File(p.getOutputJarPath()); stub_gen.generateStubbedJar(dst_jar, classes, p.getFilter()); } diff --git a/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java b/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java index f5a339d40..3f7c438c4 100644 --- a/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java +++ b/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java @@ -16,6 +16,7 @@ package com.android.mkstubs; +import com.android.mkstubs.Main.Logger; import com.android.mkstubs.sourcer.ClassSourcer; import com.android.mkstubs.sourcer.Output; @@ -38,17 +39,23 @@ import java.util.Map.Entry; */ class SourceGenerator { + private Logger mLog; + + public SourceGenerator(Logger log) { + mLog = log; + } + /** * Generate source for the stubbed classes, mostly for debug purposes. - * @throws IOException + * @throws IOException */ public void generateSource(File baseDir, Map classes, Filter filter) throws IOException { - + for (Entry entry : classes.entrySet()) { ClassReader cr = entry.getValue(); - + String name = classNameToJavaPath(cr.getClassName()); FileWriter fw = null; @@ -64,9 +71,9 @@ class SourceGenerator { FileWriter createWriter(File baseDir, String name) throws IOException { File f = new File(baseDir, name); f.getParentFile().mkdirs(); - - System.out.println("Writing " + f.getPath()); - + + mLog.debug("Writing " + f.getPath()); + return new FileWriter(f); } @@ -83,10 +90,10 @@ class SourceGenerator { * minus all exclusions */ void visitClassSource(Writer fw, ClassReader cr, Filter filter) { - System.out.println("Dump " + cr.getClassName()); - + mLog.debug("Dump " + cr.getClassName()); + ClassVisitor javaWriter = new ClassSourcer(new Output(fw)); - ClassVisitor classFilter = new FilterClassAdapter(javaWriter, filter); + ClassVisitor classFilter = new FilterClassAdapter(javaWriter, filter, mLog); cr.accept(classFilter, 0 /*flags*/); } diff --git a/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java b/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java index 6126e17cc..47195fa8a 100644 --- a/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java +++ b/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java @@ -16,6 +16,7 @@ package com.android.mkstubs; +import com.android.mkstubs.Main.Logger; import com.android.mkstubs.stubber.ClassStubber; import org.objectweb.asm.ClassReader; @@ -26,8 +27,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Map; -import java.util.TreeMap; import java.util.Map.Entry; +import java.util.TreeMap; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; @@ -40,9 +41,15 @@ import java.util.jar.JarOutputStream; */ class StubGenerator { + private Logger mLog; + + public StubGenerator(Logger log) { + mLog = log; + } + /** * Generate source for the stubbed classes, mostly for debug purposes. - * @throws IOException + * @throws IOException */ public void generateStubbedJar(File destJar, Map classes, @@ -52,7 +59,7 @@ class StubGenerator { for (Entry entry : classes.entrySet()) { ClassReader cr = entry.getValue(); - + byte[] b = visitClassStubber(cr, filter); String name = classNameToEntryPath(cr.getClassName()); all.put(name, b); @@ -60,7 +67,7 @@ class StubGenerator { createJar(new FileOutputStream(destJar), all); - System.out.println(String.format("Wrote %s", destJar.getPath())); + mLog.debug("Wrote %s", destJar.getPath()); } /** @@ -73,8 +80,8 @@ class StubGenerator { /** * Writes the JAR file. - * - * @param outStream The file output stream were to write the JAR. + * + * @param outStream The file output stream were to write the JAR. * @param all The map of all classes to output. * @throws IOException if an I/O error has occurred */ @@ -90,16 +97,16 @@ class StubGenerator { jar.flush(); jar.close(); } - + byte[] visitClassStubber(ClassReader cr, Filter filter) { - System.out.println("Stub " + cr.getClassName()); + mLog.debug("Stub " + cr.getClassName()); // Rewrite the new class from scratch, without reusing the constant pool from the // original class reader. ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor stubWriter = new ClassStubber(cw); - ClassVisitor classFilter = new FilterClassAdapter(stubWriter, filter); + ClassVisitor classFilter = new FilterClassAdapter(stubWriter, filter, mLog); cr.accept(classFilter, 0 /*flags*/); return cw.toByteArray(); } diff --git a/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java b/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java index 5b1f3a98e..2a71f4fd0 100644 --- a/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java +++ b/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java @@ -17,6 +17,8 @@ package com.android.mkstubs; +import com.android.mkstubs.Main.Logger; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -26,7 +28,7 @@ import org.objectweb.asm.ClassReader; import java.io.StringWriter; /** - * + * */ public class SourceGeneratorTest { @@ -34,21 +36,21 @@ public class SourceGeneratorTest { @Before public void setUp() throws Exception { - mGen = new SourceGenerator(); + mGen = new SourceGenerator(new Logger(false)); } @After public void tearDown() throws Exception { } - + @Test public void testDumpClass() throws Exception { StringWriter sw = new StringWriter(); ClassReader cr = new ClassReader("data/TestBaseClass"); - + mGen.visitClassSource(sw, cr, new Filter()); - + String s = sw.toString(); Assert.assertNotNull(s); }