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. + *

+ * 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 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 classes, Filter filter) { Set keys = classes.keySet(); for(Iterator 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: + *

+ *

+ * The {@link #accept(String)} method examines a given string against the known + * pattern to decide if it should be included. */ class Filter { private TreeSet mIncludePrefix = new TreeSet(); @@ -27,22 +35,44 @@ class Filter { private TreeSet mExcludePrefix = new TreeSet(); private TreeSet mExcludeFull = new TreeSet(); + /** + * Returns the set of all full patterns to be included. + */ public TreeSet getIncludeFull() { return mIncludeFull; } - + + /** + * Returns the set of all prefix patterns to be included. + */ public TreeSet getIncludePrefix() { return mIncludePrefix; } + /** + * Returns the set of all full patterns to be excluded. + */ public TreeSet getExcludeFull() { return mExcludeFull; } + /** + * Returns the set of all prefix patterns to be excluded. + */ public TreeSet getExcludePrefix() { return mExcludePrefix; } - + + /** + * Checks if the given string passes the various include/exclude rules. + * The matching is done as follows: + *

+ * @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. + *

+ * 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: + *

+ * @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: + * + * 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: + * + */ private void process(Params p) throws IOException { AsmAnalyzer aa = new AsmAnalyzer(); Map 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. + *

+ * 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. + *

+ * 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. + *

+ * 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". + *

+ * 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}. + *

+ * 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}. + *

+ * 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. *

- * 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.. + *

+ * Note: most of the implementation is a duplicate of ASM's SignatureWriter with some + * slight variations. + *

+ * 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 not 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 this + * signature. Initially null. + */ private SignatureSourcer mReturnType; + /** + * {@link SignatureSourcer} generated when parsing the super class of this + * signature. Initially null. + */ private SignatureSourcer mSuperClass; + /** + * {@link SignatureSourcer}s for each parameters generated when parsing the method parameters + * of this signature. Initially empty but not null. + */ private ArrayList mParameters = new ArrayList(); 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. + *

+ * Annotations and parameters are passed as-is. + * All other code is replaced by the following: + *

throw new RuntimeException("stub");
+ * Note that constructors rewritten this way will probably fail with the runtime bytecode + * verifier since no call to super is generated. */ public class MethodStubber extends MethodAdapter {