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;
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user