diff options
15 files changed, 206 insertions, 39 deletions
diff --git a/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java b/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java index 0a37f297f..5e64ae6c4 100644 --- a/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java +++ b/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java @@ -28,7 +28,10 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** - * + * Analyzes an input Jar to get all the relevant classes according to the given filter. + * <p/> + * This is mostly a helper extracted for convenience. Callers will want to use + * {@link #parseInputJar(String)} followed by {@link #filter(Map, Filter)}. */ class AsmAnalyzer { @@ -66,12 +69,22 @@ class AsmAnalyzer { } } - public void filter(Map<String, ClassReader> classes, Filter filter) { + /** + * 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. + */ + void filter(Map<String, ClassReader> classes, Filter filter) { Set<String> keys = classes.keySet(); for(Iterator<String> 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); diff --git a/tools/mkstubs/src/com/android/mkstubs/Filter.java b/tools/mkstubs/src/com/android/mkstubs/Filter.java index c566c6b00..0dcd8daa0 100644 --- a/tools/mkstubs/src/com/android/mkstubs/Filter.java +++ b/tools/mkstubs/src/com/android/mkstubs/Filter.java @@ -19,7 +19,15 @@ package com.android.mkstubs; import java.util.TreeSet; /** - * + * A "filter" holds the various patterns that MkStubs should accept (include) + * or reject (exclude). Patterns can be of two kind: + * <ul> + * <li>Full patterns are simple string matches, similar to a "^pattern$" regex. + * <li>Prefix patterns are partial string matches, similar to a "^pattern.*" regex. + * </ul> + * <p/> + * The {@link #accept(String)} method examines a given string against the known + * pattern to decide if it should be included. */ class Filter { private TreeSet<String> mIncludePrefix = new TreeSet<String>(); @@ -27,22 +35,44 @@ class Filter { private TreeSet<String> mExcludePrefix = new TreeSet<String>(); private TreeSet<String> mExcludeFull = new TreeSet<String>(); + /** + * Returns the set of all full patterns to be included. + */ public TreeSet<String> getIncludeFull() { return mIncludeFull; } - + + /** + * Returns the set of all prefix patterns to be included. + */ public TreeSet<String> getIncludePrefix() { return mIncludePrefix; } + /** + * Returns the set of all full patterns to be excluded. + */ public TreeSet<String> getExcludeFull() { return mExcludeFull; } + /** + * Returns the set of all prefix patterns to be excluded. + */ public TreeSet<String> getExcludePrefix() { return mExcludePrefix; } - + + /** + * Checks if the given string passes the various include/exclude rules. + * The matching is done as follows: + * <ul> + * <li> The string must match either a full include or a prefix include. + * <li> The string must not match any full exclude nor any prefix exclude. + * </ul> + * @param s The string to accept or reject. + * @return True if the string can be accepted, false if it must be rejected. + */ public boolean accept(String s) { // Check if it can be included. diff --git a/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java b/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java index c3585a847..d3b06f736 100644 --- a/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java +++ b/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java @@ -25,7 +25,8 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** - * A class visitor that filters out all the referenced exclusions + * A class visitor that filters out all members (fields, methods and inner classes) that are + * either private or rejected by the {@link Filter}. */ class FilterClassAdapter extends ClassAdapter { diff --git a/tools/mkstubs/src/com/android/mkstubs/Main.java b/tools/mkstubs/src/com/android/mkstubs/Main.java index fd8fa4d9d..01cda71c8 100644 --- a/tools/mkstubs/src/com/android/mkstubs/Main.java +++ b/tools/mkstubs/src/com/android/mkstubs/Main.java @@ -26,10 +26,15 @@ import java.util.Map; /** - * + * Main entry point of the MkStubs app. + * <p/> + * 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) + */ static class Params { private String mInputJarPath; private String mOutputJarPath; @@ -40,22 +45,25 @@ public class Main { mOutputJarPath = outputJarPath; mFilter = new Filter(); } - + + /** Returns the name of the input jar, where to read classes from. */ public String getInputJarPath() { return mInputJarPath; } + /** Returns the name of the output jar, where to write classes to. */ public String getOutputJarPath() { return mOutputJarPath; } - + + /** Returns the current instance of the filter, the include/exclude patterns. */ public Filter getFilter() { return mFilter; } } /** - * @param args + * Main entry point. Processes arguments then performs the "real" work. */ public static void main(String[] args) { @@ -68,6 +76,17 @@ public class Main { } } + /** + * Grabs command-line arguments. + * The expected arguments are: + * <ul> + * <li> The filename of the input Jar. + * <li> The filename of the output Jar. + * <li> One or more include/exclude patterns or files containing these patterns. + * See {@link #addString(Params, String)} for syntax. + * </ul> + * @throws IOException on failure to read a pattern file. + */ private Params processArgs(String[] args) throws IOException { if (args.length < 2) { @@ -83,7 +102,26 @@ public class Main { return p; } + /** + * Adds one pattern string to the current filter. + * The syntax must be: + * <ul> + * <li> +full_include or +prefix_include* + * <li> -full_exclude or -prefix_exclude* + * <li> @filename + * </ul> + * 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 + */ private void addString(Params p, String s) throws IOException { + if (s == null) { + return; + } + s = s.trim(); if (s.length() < 2) { @@ -114,11 +152,20 @@ public class Main { } } - private void addStringsFromFile(Params p, String inputFile) + /** + * 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) throws IOException { BufferedReader br = null; try { - br = new BufferedReader(new FileReader(inputFile)); + br = new BufferedReader(new FileReader(osFilePath)); String line; while ((line = br.readLine()) != null) { addString(p, line); @@ -128,6 +175,9 @@ public class Main { } } + /** + * Prints some help to stdout. + */ private void usage() { System.out.println("Usage: mkstub input.jar output.jar [excluded-class @excluded-classes-file ...]"); @@ -144,6 +194,17 @@ public class Main { System.exit(1); } + /** + * Performs the main workflow of this app: + * <ul> + * <li> Read the input Jar to get all its classes. + * <li> Filter out all classes that should not be included or that should be excluded. + * <li> Goes thru the classes, filters methods/fields and generate their source + * in a directory called "<outpath_jar_path>_sources" + * <li> Does the same filtering on the classes but this time generates the real stubbed + * output jar. + * </ul> + */ private void process(Params p) throws IOException { AsmAnalyzer aa = new AsmAnalyzer(); Map<String, ClassReader> classes = aa.parseInputJar(p.getInputJarPath()); diff --git a/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java b/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java index 461a25f13..f5a339d40 100644 --- a/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java +++ b/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java @@ -30,7 +30,11 @@ import java.util.Map; import java.util.Map.Entry; /** - * + * Given a set of already filtered classes, this filters out all private members and then + * generates the Java source for the remaining classes. + * <p/> + * This is an helper extracted for convenience. Callers just need to use + * {@link #generateSource(File, Map, Filter)}. */ class SourceGenerator { diff --git a/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java b/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java index 0321dc325..6126e17cc 100644 --- a/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java +++ b/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java @@ -32,7 +32,11 @@ import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; /** - * + * Given a set of already filtered classes, this filters out all private members, + * stubs the remaining classes and then generates a Jar out of them. + * <p/> + * This is an helper extracted for convenience. Callers just need to use + * {@link #generateStubbedJar(File, Map, Filter)}. */ class StubGenerator { diff --git a/tools/mkstubs/src/com/android/mkstubs/sourcer/AccessSourcer.java b/tools/mkstubs/src/com/android/mkstubs/sourcer/AccessSourcer.java index 757dcea15..3b14ea711 100644 --- a/tools/mkstubs/src/com/android/mkstubs/sourcer/AccessSourcer.java +++ b/tools/mkstubs/src/com/android/mkstubs/sourcer/AccessSourcer.java @@ -19,7 +19,11 @@ package com.android.mkstubs.sourcer; import org.objectweb.asm.Opcodes; /** - * + * Source generator for the access fields of methods, fields and classes. + * <p/> + * Given an integer access field and a type ({@link #IS_CLASS}, {@link #IS_FIELD} or + * {@link #IS_METHOD}), the {@link #write(int, int)} method can generate a string + * desribing the access modifiers for a Java source. */ class AccessSourcer { @@ -81,6 +85,9 @@ class AccessSourcer { /** * Generates a list of access keywords, e.g. "public final". + * <p/> + * It is up to the caller to filter extra keywords that should not be generated, + * e.g. {@link Flag#ACC_SYNTHETIC}. * * @param access The access mode, e.g. 33 or 18 * @param filter One of {@link #IS_CLASS}, {@link #IS_FIELD} or {@link #IS_METHOD}, which diff --git a/tools/mkstubs/src/com/android/mkstubs/sourcer/AnnotationSourcer.java b/tools/mkstubs/src/com/android/mkstubs/sourcer/AnnotationSourcer.java index bbf1cb257..d2843a8ef 100644 --- a/tools/mkstubs/src/com/android/mkstubs/sourcer/AnnotationSourcer.java +++ b/tools/mkstubs/src/com/android/mkstubs/sourcer/AnnotationSourcer.java @@ -19,7 +19,7 @@ package com.android.mkstubs.sourcer; import org.objectweb.asm.AnnotationVisitor; /** - * + * An annotation visitor that generates Java source for an annotation. */ class AnnotationSourcer implements AnnotationVisitor { diff --git a/tools/mkstubs/src/com/android/mkstubs/sourcer/ClassSourcer.java b/tools/mkstubs/src/com/android/mkstubs/sourcer/ClassSourcer.java index 189e1a007..3d95039bd 100644 --- a/tools/mkstubs/src/com/android/mkstubs/sourcer/ClassSourcer.java +++ b/tools/mkstubs/src/com/android/mkstubs/sourcer/ClassSourcer.java @@ -25,7 +25,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.signature.SignatureReader; /** - * A class visitor that rewrites a java source + * A class visitor that writes a java source. */ public class ClassSourcer implements ClassVisitor { diff --git a/tools/mkstubs/src/com/android/mkstubs/sourcer/FieldSourcer.java b/tools/mkstubs/src/com/android/mkstubs/sourcer/FieldSourcer.java index 4f9c229cc..7f30a2440 100644 --- a/tools/mkstubs/src/com/android/mkstubs/sourcer/FieldSourcer.java +++ b/tools/mkstubs/src/com/android/mkstubs/sourcer/FieldSourcer.java @@ -19,10 +19,11 @@ package com.android.mkstubs.sourcer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; /** - * + * A field visitor that generates Java source defining a field. */ class FieldSourcer implements FieldVisitor { @@ -56,7 +57,7 @@ class FieldSourcer implements FieldVisitor { as.write(mAccess, AccessSourcer.IS_FIELD); if (mSignature == null) { - mOutput.write(" %s", mOutput.decodeDesc(mDesc)); + mOutput.write(" %s", Type.getType(mDesc).getClassName()); } else { mOutput.write(" "); SignatureReader sigReader = new SignatureReader(mSignature); diff --git a/tools/mkstubs/src/com/android/mkstubs/sourcer/MethodSourcer.java b/tools/mkstubs/src/com/android/mkstubs/sourcer/MethodSourcer.java index d474e4b7c..f58de3249 100644 --- a/tools/mkstubs/src/com/android/mkstubs/sourcer/MethodSourcer.java +++ b/tools/mkstubs/src/com/android/mkstubs/sourcer/MethodSourcer.java @@ -26,7 +26,7 @@ import org.objectweb.asm.signature.SignatureReader; import java.util.ArrayList; /** - * + * A method visitor that generates the Java source for a whole method. */ class MethodSourcer implements MethodVisitor { diff --git a/tools/mkstubs/src/com/android/mkstubs/sourcer/Output.java b/tools/mkstubs/src/com/android/mkstubs/sourcer/Output.java index 837cf9516..bc2218fcd 100644 --- a/tools/mkstubs/src/com/android/mkstubs/sourcer/Output.java +++ b/tools/mkstubs/src/com/android/mkstubs/sourcer/Output.java @@ -16,22 +16,38 @@ package com.android.mkstubs.sourcer; -import org.objectweb.asm.Type; - import java.io.IOException; import java.io.Writer; /** - * + * An {@link Output} objects is an helper to write to a character stream {@link Writer}. + * <p/> + * It provide some helper methods to the various "sourcer" classes from this package + * to help them write to the underlying stream. */ public class Output { private final Writer mWriter; + /** + * Creates a new {@link Output} object that wraps the given {@link Writer}. + * <p/> + * The caller is responsible of opening and closing the {@link Writer}. + * + * @param writer The writer to write to. Could be a file, a string, etc. + */ public Output(Writer writer) { mWriter = writer; } + /** + * Writes a formatted string to the writer. + * + * @param format The format string. + * @param args The arguments for the format string. + * + * @see String#format(String, Object...) + */ public void write(String format, Object... args) { try { mWriter.write(String.format(format, args)); @@ -40,18 +56,21 @@ public class Output { } } + /** + * Writes a single character to the writer. + * + * @param c The character to write. + */ public void write(char c) { write(Character.toString(c)); } + /** + * Writes a {@link StringBuilder} to the writer. + * + * @param sb The {@link StringBuilder#toString()} method is used to ge the string to write. + */ public void write(StringBuilder sb) { write(sb.toString()); } - - - public String decodeDesc(String desc) { - return Type.getType(desc).getClassName(); - } - - } diff --git a/tools/mkstubs/src/com/android/mkstubs/sourcer/SignatureSourcer.java b/tools/mkstubs/src/com/android/mkstubs/sourcer/SignatureSourcer.java index 6202528c4..7805d7df8 100644 --- a/tools/mkstubs/src/com/android/mkstubs/sourcer/SignatureSourcer.java +++ b/tools/mkstubs/src/com/android/mkstubs/sourcer/SignatureSourcer.java @@ -24,14 +24,22 @@ import org.objectweb.asm.signature.SignatureWriter; import java.util.ArrayList; /** - * Note: most of the implementation is a duplicate of - * ASM's SignatureWriter with some slight variations. + * A signature visitor that can be used to generate Java source corresponding to + * various types of signatures. * <p/> - * Note: When processing a method's signature, the signature order is the - * reverse of the source order, e.g. it is (parameters)return-type where - * we want to generate "return-type method-name (parameters)". - * So in this case the return-type and parameters are not output directly - * but are instead accumulated in internal variables. + * Terminology: a "signature" is a type descriptor for generics. There are different types + * of signatures depending on the context where they are used, e.g. method declarations, + * method parameters, class declarations, etc.. + * <p/> + * Note: most of the implementation is a duplicate of ASM's SignatureWriter with some + * slight variations. + * <p/> + * Note: When processing a method's signature, the signature order is the reverse of the source + * order, e.g. the signature is written as "(parameters)return-type" where we want to generate + * "return-type method-name (parameters)". To hanlde this case, the return-type and parameters + * are <em>not</em> output directly but are instead accumulated in internal variables that you can + * get later using {@link #getReturnType()}, {@link #getParameters()}, {@link #getSuperClass()} + * and {@link #formalsToString()}. */ class SignatureSourcer implements SignatureVisitor { @@ -58,10 +66,22 @@ class SignatureSourcer implements SignatureVisitor { */ private int mArgumentStack; + /** + * {@link SignatureSourcer} generated when parsing the return type of <em>this</em> + * signature. Initially null. + */ private SignatureSourcer mReturnType; + /** + * {@link SignatureSourcer} generated when parsing the super class of <em>this</em> + * signature. Initially null. + */ private SignatureSourcer mSuperClass; + /** + * {@link SignatureSourcer}s for each parameters generated when parsing the method parameters + * of <em>this</em> signature. Initially empty but not null. + */ private ArrayList<SignatureSourcer> mParameters = new ArrayList<SignatureSourcer>(); diff --git a/tools/mkstubs/src/com/android/mkstubs/stubber/ClassStubber.java b/tools/mkstubs/src/com/android/mkstubs/stubber/ClassStubber.java index dea0a5298..8f9ae113c 100644 --- a/tools/mkstubs/src/com/android/mkstubs/stubber/ClassStubber.java +++ b/tools/mkstubs/src/com/android/mkstubs/stubber/ClassStubber.java @@ -24,7 +24,8 @@ import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; /** - * + * A class visitor that generates stubs for all methods of the visited class. + * Everything else is passed as-is. */ public class ClassStubber extends ClassAdapter { diff --git a/tools/mkstubs/src/com/android/mkstubs/stubber/MethodStubber.java b/tools/mkstubs/src/com/android/mkstubs/stubber/MethodStubber.java index 3e200cd94..161780995 100644 --- a/tools/mkstubs/src/com/android/mkstubs/stubber/MethodStubber.java +++ b/tools/mkstubs/src/com/android/mkstubs/stubber/MethodStubber.java @@ -24,7 +24,13 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** - * + * A method visitor that generates a code stub for the visited method. + * <p/> + * Annotations and parameters are passed as-is. + * All other code is replaced by the following: + * <pre>throw new RuntimeException("stub");</pre> + * Note that constructors rewritten this way will probably fail with the runtime bytecode + * verifier since no call to <code>super</code> is generated. */ public class MethodStubber extends MethodAdapter { |
