am 5eafc91a: Merge "merge "SDK: make \'mkstub\' less verbose." from HC. Do not merge." into gingerbread

* commit '5eafc91ad3216561d2287f327580644fb1e04cfb':
  merge "SDK: make 'mkstub' less verbose." from HC. Do not merge.
This commit is contained in:
Raphael
2011-02-04 14:49:19 -08:00
committed by Android Git Automerger
6 changed files with 168 additions and 65 deletions

View File

@@ -16,6 +16,8 @@
package com.android.mkstubs; package com.android.mkstubs;
import com.android.mkstubs.Main.Logger;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import java.io.IOException; import java.io.IOException;
@@ -53,7 +55,7 @@ class AsmAnalyzer {
classes.put(className, cr); classes.put(className, cr);
} }
} }
return classes; return classes;
} }
@@ -72,25 +74,26 @@ class AsmAnalyzer {
/** /**
* Filters the set of classes. Removes all classes that should not be included in the * 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. * 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 * @param classes The in-out map of classes to examine and filter. The map is filtered
* in-place. * in-place.
* @param filter A filter describing which classes to include and which ones to exclude. * @param filter A filter describing which classes to include and which ones to exclude.
* @param log
*/ */
void filter(Map<String, ClassReader> classes, Filter filter) { void filter(Map<String, ClassReader> classes, Filter filter, Logger log) {
Set<String> keys = classes.keySet(); Set<String> keys = classes.keySet();
for(Iterator<String> it = keys.iterator(); it.hasNext(); ) { for(Iterator<String> it = keys.iterator(); it.hasNext(); ) {
String key = it.next(); String key = it.next();
// TODO: We *could* filter out all private classes here: classes.get(key).getAccess(). // TODO: We *could* filter out all private classes here: classes.get(key).getAccess().
// remove if we don't keep it // remove if we don't keep it
if (!filter.accept(key)) { if (!filter.accept(key)) {
System.out.println("- Remove class " + key); log.debug("- Remove class " + key);
it.remove(); it.remove();
} }
} }
} }
} }

View File

@@ -16,6 +16,8 @@
package com.android.mkstubs; package com.android.mkstubs;
import com.android.mkstubs.Main.Logger;
import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute; import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassAdapter;
@@ -30,12 +32,14 @@ import org.objectweb.asm.Opcodes;
*/ */
class FilterClassAdapter extends ClassAdapter { class FilterClassAdapter extends ClassAdapter {
private final Logger mLog;
private final Filter mFilter; private final Filter mFilter;
private String mClassName; private String mClassName;
public FilterClassAdapter(ClassVisitor writer, Filter filter) { public FilterClassAdapter(ClassVisitor writer, Filter filter, Logger log) {
super(writer); super(writer);
mFilter = filter; mFilter = filter;
mLog = log;
} }
@Override @Override
@@ -73,7 +77,7 @@ class FilterClassAdapter extends ClassAdapter {
String filterName = String.format("%s#%s", mClassName, name); String filterName = String.format("%s#%s", mClassName, name);
if (!mFilter.accept(filterName)) { if (!mFilter.accept(filterName)) {
System.out.println("- Remove field " + filterName); mLog.debug("- Remove field " + filterName);
return null; return null;
} }
@@ -105,7 +109,7 @@ class FilterClassAdapter extends ClassAdapter {
String filterName = String.format("%s#%s%s", mClassName, name, desc); String filterName = String.format("%s#%s%s", mClassName, name, desc);
if (!mFilter.accept(filterName)) { if (!mFilter.accept(filterName)) {
System.out.println("- Remove method " + filterName); mLog.debug("- Remove method " + filterName);
return null; return null;
} }
@@ -114,7 +118,7 @@ class FilterClassAdapter extends ClassAdapter {
filterName = String.format("%s#%s%s", mClassName, name, signature); filterName = String.format("%s#%s%s", mClassName, name, signature);
if (!mFilter.accept(filterName)) { if (!mFilter.accept(filterName)) {
System.out.println("- Remove method " + filterName); mLog.debug("- Remove method " + filterName);
return null; return null;
} }
} }

View File

@@ -16,6 +16,8 @@
package com.android.mkstubs; package com.android.mkstubs;
import com.android.mkstubs.Main.Params;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import java.io.BufferedReader; import java.io.BufferedReader;
@@ -31,7 +33,7 @@ import java.util.Map;
* For workflow details, see {@link #process(Params)}. * For workflow details, see {@link #process(Params)}.
*/ */
public class Main { public class Main {
/** /**
* A struct-like class to hold the various input values (e.g. command-line args) * 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 mInputJarPath;
private String mOutputJarPath; private String mOutputJarPath;
private Filter mFilter; private Filter mFilter;
private boolean mVerbose;
public Params(String inputJarPath, String outputJarPath) { private boolean mDumpSource;
mInputJarPath = inputJarPath;
mOutputJarPath = outputJarPath; public Params() {
mFilter = new Filter(); 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. */ /** Returns the name of the input jar, where to read classes from. */
public String getInputJarPath() { public String getInputJarPath() {
return mInputJarPath; return mInputJarPath;
@@ -60,13 +72,53 @@ public class Main {
public Filter getFilter() { public Filter getFilter() {
return mFilter; 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. * Main entry point. Processes arguments then performs the "real" work.
*/ */
public static void main(String[] args) { public static void main(String[] args) {
Main m = new Main(); Main m = new Main();
try { try {
Params p = m.processArgs(args); Params p = m.processArgs(args);
@@ -88,17 +140,32 @@ public class Main {
* @throws IOException on failure to read a pattern file. * @throws IOException on failure to read a pattern file.
*/ */
private Params processArgs(String[] args) throws IOException { private Params processArgs(String[] args) throws IOException {
Params p = new Params();
if (args.length < 2) {
usage(); 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]); if (p.getInputJarPath() == null && p.getOutputJarPath() == null) {
usage("Missing input or output JAR.");
for (int i = 2; i < args.length; i++) {
addString(p, args[i]);
} }
return p; return p;
} }
@@ -112,7 +179,7 @@ public class Main {
* </ul> * </ul>
* The input string is trimmed so any space around the first letter (-/+/@) or * The input string is trimmed so any space around the first letter (-/+/@) or
* at the end is removed. Empty strings are ignored. * at the end is removed. Empty strings are ignored.
* *
* @param p The params which filters to edit. * @param p The params which filters to edit.
* @param s The string to examine. * @param s The string to examine.
* @throws IOException * @throws IOException
@@ -127,13 +194,13 @@ public class Main {
if (s.length() < 2) { if (s.length() < 2) {
return; return;
} }
char mode = s.charAt(0); char mode = s.charAt(0);
s = s.substring(1).trim(); s = s.substring(1).trim();
if (mode == '@') { if (mode == '@') {
addStringsFromFile(p, s); addStringsFromFile(p, s);
} else if (mode == '-') { } else if (mode == '-') {
s = s.replace('.', '/'); // transform FQCN into ASM internal name s = s.replace('.', '/'); // transform FQCN into ASM internal name
if (s.endsWith("*")) { if (s.endsWith("*")) {
@@ -154,11 +221,11 @@ public class Main {
/** /**
* Adds all the filter strings from the given file. * Adds all the filter strings from the given file.
* *
* @param p The params which filter to edit. * @param p The params which filter to edit.
* @param osFilePath The OS path to the file containing the patterns. * @param osFilePath The OS path to the file containing the patterns.
* @throws IOException * @throws IOException
* *
* @see #addString(Params, String) * @see #addString(Params, String)
*/ */
private void addStringsFromFile(Params p, String osFilePath) private void addStringsFromFile(Params p, String osFilePath)
@@ -179,9 +246,19 @@ public class Main {
/** /**
* Prints some help to stdout. * Prints some help to stdout.
* @param error The error that generated the usage, if any. Can be null.
*/ */
private void usage() { private void usage(String error) {
System.out.println("Usage: mkstub input.jar output.jar [excluded-class @excluded-classes-file ...]"); 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" + System.out.println("Include syntax:\n" +
"+com.package.* : whole package, with glob\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[$Inner] or ...Class*: whole classes with optional glob\n" +
"-com.package.Class#method: whole method or field\n" + "-com.package.Class#method: whole method or field\n" +
"-com.package.Class#method(IILjava/lang/String;)V: specific method with signature.\n\n"); "-com.package.Class#method(IILjava/lang/String;)V: specific method with signature.\n\n");
System.exit(1); System.exit(1);
} }
@@ -211,20 +289,22 @@ public class Main {
AsmAnalyzer aa = new AsmAnalyzer(); AsmAnalyzer aa = new AsmAnalyzer();
Map<String, ClassReader> classes = aa.parseInputJar(p.getInputJarPath()); Map<String, ClassReader> classes = aa.parseInputJar(p.getInputJarPath());
System.out.println(String.format("Classes loaded: %d", classes.size())); Logger log = new Logger(p.isVerbose());
log.info("Classes loaded: %d", classes.size());
aa.filter(classes, p.getFilter());
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 // dump as Java source files, mostly for debugging
SourceGenerator src_gen = new SourceGenerator(); if (p.isDumpSource()) {
File dst_src_dir = new File(p.getOutputJarPath() + "_sources"); SourceGenerator src_gen = new SourceGenerator(log);
dst_src_dir.mkdir(); File dst_src_dir = new File(p.getOutputJarPath() + "_sources");
src_gen.generateSource(dst_src_dir, classes, p.getFilter()); dst_src_dir.mkdir();
src_gen.generateSource(dst_src_dir, classes, p.getFilter());
}
// dump the stubbed jar // dump the stubbed jar
StubGenerator stub_gen = new StubGenerator(); StubGenerator stub_gen = new StubGenerator(log);
File dst_jar = new File(p.getOutputJarPath()); File dst_jar = new File(p.getOutputJarPath());
stub_gen.generateStubbedJar(dst_jar, classes, p.getFilter()); stub_gen.generateStubbedJar(dst_jar, classes, p.getFilter());
} }

View File

@@ -16,6 +16,7 @@
package com.android.mkstubs; package com.android.mkstubs;
import com.android.mkstubs.Main.Logger;
import com.android.mkstubs.sourcer.ClassSourcer; import com.android.mkstubs.sourcer.ClassSourcer;
import com.android.mkstubs.sourcer.Output; import com.android.mkstubs.sourcer.Output;
@@ -38,17 +39,23 @@ import java.util.Map.Entry;
*/ */
class SourceGenerator { class SourceGenerator {
private Logger mLog;
public SourceGenerator(Logger log) {
mLog = log;
}
/** /**
* Generate source for the stubbed classes, mostly for debug purposes. * Generate source for the stubbed classes, mostly for debug purposes.
* @throws IOException * @throws IOException
*/ */
public void generateSource(File baseDir, public void generateSource(File baseDir,
Map<String, ClassReader> classes, Map<String, ClassReader> classes,
Filter filter) throws IOException { Filter filter) throws IOException {
for (Entry<String, ClassReader> entry : classes.entrySet()) { for (Entry<String, ClassReader> entry : classes.entrySet()) {
ClassReader cr = entry.getValue(); ClassReader cr = entry.getValue();
String name = classNameToJavaPath(cr.getClassName()); String name = classNameToJavaPath(cr.getClassName());
FileWriter fw = null; FileWriter fw = null;
@@ -64,9 +71,9 @@ class SourceGenerator {
FileWriter createWriter(File baseDir, String name) throws IOException { FileWriter createWriter(File baseDir, String name) throws IOException {
File f = new File(baseDir, name); File f = new File(baseDir, name);
f.getParentFile().mkdirs(); f.getParentFile().mkdirs();
System.out.println("Writing " + f.getPath()); mLog.debug("Writing " + f.getPath());
return new FileWriter(f); return new FileWriter(f);
} }
@@ -83,10 +90,10 @@ class SourceGenerator {
* minus all exclusions * minus all exclusions
*/ */
void visitClassSource(Writer fw, ClassReader cr, Filter filter) { 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 javaWriter = new ClassSourcer(new Output(fw));
ClassVisitor classFilter = new FilterClassAdapter(javaWriter, filter); ClassVisitor classFilter = new FilterClassAdapter(javaWriter, filter, mLog);
cr.accept(classFilter, 0 /*flags*/); cr.accept(classFilter, 0 /*flags*/);
} }

View File

@@ -16,6 +16,7 @@
package com.android.mkstubs; package com.android.mkstubs;
import com.android.mkstubs.Main.Logger;
import com.android.mkstubs.stubber.ClassStubber; import com.android.mkstubs.stubber.ClassStubber;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
@@ -26,8 +27,8 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream; import java.util.jar.JarOutputStream;
@@ -40,9 +41,15 @@ import java.util.jar.JarOutputStream;
*/ */
class StubGenerator { class StubGenerator {
private Logger mLog;
public StubGenerator(Logger log) {
mLog = log;
}
/** /**
* Generate source for the stubbed classes, mostly for debug purposes. * Generate source for the stubbed classes, mostly for debug purposes.
* @throws IOException * @throws IOException
*/ */
public void generateStubbedJar(File destJar, public void generateStubbedJar(File destJar,
Map<String, ClassReader> classes, Map<String, ClassReader> classes,
@@ -52,7 +59,7 @@ class StubGenerator {
for (Entry<String, ClassReader> entry : classes.entrySet()) { for (Entry<String, ClassReader> entry : classes.entrySet()) {
ClassReader cr = entry.getValue(); ClassReader cr = entry.getValue();
byte[] b = visitClassStubber(cr, filter); byte[] b = visitClassStubber(cr, filter);
String name = classNameToEntryPath(cr.getClassName()); String name = classNameToEntryPath(cr.getClassName());
all.put(name, b); all.put(name, b);
@@ -60,7 +67,7 @@ class StubGenerator {
createJar(new FileOutputStream(destJar), all); 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. * 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. * @param all The map of all classes to output.
* @throws IOException if an I/O error has occurred * @throws IOException if an I/O error has occurred
*/ */
@@ -90,16 +97,16 @@ class StubGenerator {
jar.flush(); jar.flush();
jar.close(); jar.close();
} }
byte[] visitClassStubber(ClassReader cr, Filter filter) { 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 // Rewrite the new class from scratch, without reusing the constant pool from the
// original class reader. // original class reader.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor stubWriter = new ClassStubber(cw); ClassVisitor stubWriter = new ClassStubber(cw);
ClassVisitor classFilter = new FilterClassAdapter(stubWriter, filter); ClassVisitor classFilter = new FilterClassAdapter(stubWriter, filter, mLog);
cr.accept(classFilter, 0 /*flags*/); cr.accept(classFilter, 0 /*flags*/);
return cw.toByteArray(); return cw.toByteArray();
} }

View File

@@ -17,6 +17,8 @@
package com.android.mkstubs; package com.android.mkstubs;
import com.android.mkstubs.Main.Logger;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@@ -26,7 +28,7 @@ import org.objectweb.asm.ClassReader;
import java.io.StringWriter; import java.io.StringWriter;
/** /**
* *
*/ */
public class SourceGeneratorTest { public class SourceGeneratorTest {
@@ -34,21 +36,21 @@ public class SourceGeneratorTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mGen = new SourceGenerator(); mGen = new SourceGenerator(new Logger(false));
} }
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
} }
@Test @Test
public void testDumpClass() throws Exception { public void testDumpClass() throws Exception {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
ClassReader cr = new ClassReader("data/TestBaseClass"); ClassReader cr = new ClassReader("data/TestBaseClass");
mGen.visitClassSource(sw, cr, new Filter()); mGen.visitClassSource(sw, cr, new Filter());
String s = sw.toString(); String s = sw.toString();
Assert.assertNotNull(s); Assert.assertNotNull(s);
} }