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;
|
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;
|
||||||
@@ -76,8 +78,9 @@ class AsmAnalyzer {
|
|||||||
* @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(); ) {
|
||||||
@@ -87,7 +90,7 @@ class AsmAnalyzer {
|
|||||||
|
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
|
private boolean mDumpSource;
|
||||||
|
|
||||||
public Params(String inputJarPath, String outputJarPath) {
|
public Params() {
|
||||||
mInputJarPath = inputJarPath;
|
|
||||||
mOutputJarPath = outputJarPath;
|
|
||||||
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,15 +140,30 @@ 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) {
|
for (String arg : args) {
|
||||||
usage();
|
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;
|
||||||
@@ -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());
|
aa.filter(classes, p.getFilter(), log);
|
||||||
|
log.info("Classes filtered: %d", classes.size());
|
||||||
System.out.println(String.format("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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,6 +39,12 @@ 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
|
||||||
@@ -65,7 +72,7 @@ class SourceGenerator {
|
|||||||
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*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,6 +41,12 @@ 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
|
||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,14 +99,14 @@ class StubGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -34,7 +36,7 @@ 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
|
||||||
|
|||||||
Reference in New Issue
Block a user