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:
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.mkstubs;
|
||||
|
||||
import com.android.mkstubs.Main.Logger;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -76,8 +78,9 @@ class AsmAnalyzer {
|
||||
* @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<String, ClassReader> classes, Filter filter) {
|
||||
void filter(Map<String, ClassReader> classes, Filter filter, Logger log) {
|
||||
|
||||
Set<String> keys = classes.keySet();
|
||||
for(Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
||||
@@ -87,7 +90,7 @@ class AsmAnalyzer {
|
||||
|
||||
// remove if we don't keep it
|
||||
if (!filter.accept(key)) {
|
||||
System.out.println("- Remove class " + key);
|
||||
log.debug("- Remove class " + key);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.mkstubs;
|
||||
|
||||
import com.android.mkstubs.Main.Params;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@@ -39,13 +41,23 @@ public class Main {
|
||||
private String mInputJarPath;
|
||||
private String mOutputJarPath;
|
||||
private Filter mFilter;
|
||||
private boolean mVerbose;
|
||||
private boolean mDumpSource;
|
||||
|
||||
public Params(String inputJarPath, String outputJarPath) {
|
||||
mInputJarPath = inputJarPath;
|
||||
mOutputJarPath = outputJarPath;
|
||||
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,15 +140,30 @@ public class Main {
|
||||
* @throws IOException on failure to read a pattern file.
|
||||
*/
|
||||
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]);
|
||||
|
||||
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;
|
||||
@@ -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<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
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -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,6 +39,12 @@ 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
|
||||
@@ -65,7 +72,7 @@ class SourceGenerator {
|
||||
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*/);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +41,12 @@ 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
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,14 +99,14 @@ class StubGenerator {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -34,7 +36,7 @@ public class SourceGeneratorTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mGen = new SourceGenerator();
|
||||
mGen = new SourceGenerator(new Logger(false));
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
Reference in New Issue
Block a user