diff --git a/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java b/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java index c023cf2f5..0a37f297f 100644 --- a/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java +++ b/tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java @@ -19,9 +19,7 @@ package com.android.mkstubs; import org.objectweb.asm.ClassReader; import java.io.IOException; -import java.util.ArrayList; import java.util.Enumeration; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -68,66 +66,14 @@ class AsmAnalyzer { } } - public void filter( - Map classes, - ArrayList inclusions, - ArrayList exclusions) { + public void filter(Map classes, Filter filter) { - ArrayList inPrefix = new ArrayList(); - HashSet inFull = new HashSet (); - ArrayList exPrefix = new ArrayList(); - HashSet exFull = new HashSet (); - - for (String in : inclusions) { - if (in.endsWith("*")) { - inPrefix.add(in.substring(0, in.length() - 1)); - } else { - inFull.add(in); - } - } - - for (String ex : exclusions) { - if (ex.endsWith("*")) { - exPrefix.add(ex.substring(0, ex.length() - 1)); - } else { - exFull.add(ex); - } - } - - Set keys = classes.keySet(); for(Iterator it = keys.iterator(); it.hasNext(); ) { String key = it.next(); - - // Check if it can be included. - boolean keep = inFull.contains(key); - if (!keep) { - // Check for a prefix inclusion - for (String prefix : inPrefix) { - if (key.startsWith(prefix)) { - keep = true; - break; - } - } - } - - if (keep) { - // check for a full exclusion - keep = !exFull.contains(key); - } - if (keep) { - // or check for prefix exclusion - for (String prefix : exPrefix) { - if (key.startsWith(prefix)) { - keep = false; - break; - } - } - } - // remove if we don't keep it - if (!keep) { + if (!filter.accept(key)) { System.out.println("- Remove class " + key); it.remove(); } diff --git a/tools/mkstubs/src/com/android/mkstubs/Filter.java b/tools/mkstubs/src/com/android/mkstubs/Filter.java new file mode 100644 index 000000000..c566c6b00 --- /dev/null +++ b/tools/mkstubs/src/com/android/mkstubs/Filter.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mkstubs; + +import java.util.TreeSet; + +/** + * + */ +class Filter { + private TreeSet mIncludePrefix = new TreeSet(); + private TreeSet mIncludeFull = new TreeSet(); + private TreeSet mExcludePrefix = new TreeSet(); + private TreeSet mExcludeFull = new TreeSet(); + + public TreeSet getIncludeFull() { + return mIncludeFull; + } + + public TreeSet getIncludePrefix() { + return mIncludePrefix; + } + + public TreeSet getExcludeFull() { + return mExcludeFull; + } + + public TreeSet getExcludePrefix() { + return mExcludePrefix; + } + + public boolean accept(String s) { + + // Check if it can be included. + boolean accept = mIncludeFull.contains(s); + if (!accept) { + // Check for a prefix inclusion + for (String prefix : mIncludePrefix) { + if (s.startsWith(prefix)) { + accept = true; + break; + } + } + } + + if (accept) { + // check for a full exclusion + accept = !mExcludeFull.contains(s); + } + if (accept) { + // or check for prefix exclusion + for (String prefix : mExcludePrefix) { + if (s.startsWith(prefix)) { + accept = false; + break; + } + } + } + + return accept; + } +} diff --git a/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java b/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java index 71c55f8f6..c3585a847 100644 --- a/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java +++ b/tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java @@ -24,27 +24,24 @@ import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import java.util.List; - /** * A class visitor that filters out all the referenced exclusions */ class FilterClassAdapter extends ClassAdapter { - private final List mExclusions; + private final Filter mFilter; + private String mClassName; - public FilterClassAdapter(ClassVisitor writer, List exclusions) { + public FilterClassAdapter(ClassVisitor writer, Filter filter) { super(writer); - mExclusions = exclusions; + mFilter = filter; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - // TODO filter super type - // TODO filter interfaces - + mClassName = name; super.visit(version, access, name, signature, superName, interfaces); } @@ -71,7 +68,15 @@ class FilterClassAdapter extends ClassAdapter { return null; } - // TODO filter on name + // filter on field name + String filterName = String.format("%s#%s", mClassName, name); + + if (!mFilter.accept(filterName)) { + System.out.println("- Remove field " + filterName); + return null; + } + + // TODO we should produce an error if a filtered desc/signature is being used. return super.visitField(access, name, desc, signature, value); } @@ -95,9 +100,25 @@ class FilterClassAdapter extends ClassAdapter { return null; } - // TODO filter exceptions: error if filtered exception is being used + // filter on method name using the non-generic descriptor + String filterName = String.format("%s#%s%s", mClassName, name, desc); - // TODO filter on name; error if filtered desc or signatures is being used + if (!mFilter.accept(filterName)) { + System.out.println("- Remove method " + filterName); + return null; + } + + // filter on method name using the generic signature + if (signature != null) { + filterName = String.format("%s#%s%s", mClassName, name, signature); + + if (!mFilter.accept(filterName)) { + System.out.println("- Remove method " + filterName); + return null; + } + } + + // TODO we should produce an error if a filtered desc/signature/exception is being used. return super.visitMethod(access, name, desc, signature, exceptions); } @@ -105,7 +126,7 @@ class FilterClassAdapter extends ClassAdapter { @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - // Filter on desc type + // TODO produce an error if a filtered annotation type is being used return super.visitAnnotation(desc, visible); } @@ -122,14 +143,17 @@ class FilterClassAdapter extends ClassAdapter { return; } - // TODO filter on name + // filter on name + if (!mFilter.accept(name)) { + return; + } super.visitInnerClass(name, outerName, innerName, access); } @Override public void visitOuterClass(String owner, String name, String desc) { - // TODO Auto-generated method stub + // pass } @Override diff --git a/tools/mkstubs/src/com/android/mkstubs/Main.java b/tools/mkstubs/src/com/android/mkstubs/Main.java index 5c6e209de..fd8fa4d9d 100644 --- a/tools/mkstubs/src/com/android/mkstubs/Main.java +++ b/tools/mkstubs/src/com/android/mkstubs/Main.java @@ -22,7 +22,6 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.util.ArrayList; import java.util.Map; @@ -34,12 +33,12 @@ public class Main { static class Params { private String mInputJarPath; private String mOutputJarPath; - private ArrayList mInclusions = new ArrayList(); - private ArrayList mExclusions = new ArrayList(); - + private Filter mFilter; + public Params(String inputJarPath, String outputJarPath) { mInputJarPath = inputJarPath; mOutputJarPath = outputJarPath; + mFilter = new Filter(); } public String getInputJarPath() { @@ -49,13 +48,9 @@ public class Main { public String getOutputJarPath() { return mOutputJarPath; } - - public ArrayList getExclusions() { - return mExclusions; - } - public ArrayList getInclusions() { - return mInclusions; + public Filter getFilter() { + return mFilter; } } @@ -82,19 +77,43 @@ public class Main { Params p = new Params(args[0], args[1]); for (int i = 2; i < args.length; i++) { - String s = args[i]; - if (s.startsWith("@")) { - addStringsFromFile(p, s.substring(1)); - } else if (s.startsWith("-")) { - p.getExclusions().add(s.substring(1)); - } else if (s.startsWith("+")) { - p.getInclusions().add(s.substring(1)); - } + addString(p, args[i]); } return p; } + private void addString(Params p, String s) throws IOException { + s = s.trim(); + + if (s.length() < 2) { + return; + } + + char mode = s.charAt(0); + s = s.substring(1).trim(); + + if (mode == '@') { + addStringsFromFile(p, s); + + } else if (mode == '-') { + s = s.replace('.', '/'); // transform FQCN into ASM internal name + if (s.endsWith("*")) { + p.getFilter().getExcludePrefix().add(s.substring(0, s.length() - 1)); + } else { + p.getFilter().getExcludeFull().add(s); + } + + } else if (mode == '+') { + s = s.replace('.', '/'); // transform FQCN into ASM internal name + if (s.endsWith("*")) { + p.getFilter().getIncludePrefix().add(s.substring(0, s.length() - 1)); + } else { + p.getFilter().getIncludeFull().add(s); + } + } + } + private void addStringsFromFile(Params p, String inputFile) throws IOException { BufferedReader br = null; @@ -102,22 +121,7 @@ public class Main { br = new BufferedReader(new FileReader(inputFile)); String line; while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.length() == 0) { - continue; - } - char mode = line.charAt(0); - line = line.substring(1).trim(); - - if (line.length() > 0) { - // Keep all class names in ASM path-like format, e.g. android/view/View - line = line.replace('.', '/'); - if (mode == '-') { - p.getExclusions().add(line); - } else if (mode == '+') { - p.getInclusions().add(line); - } - } + addString(p, line); } } finally { br.close(); @@ -143,18 +147,22 @@ public class Main { private void process(Params p) throws IOException { AsmAnalyzer aa = new AsmAnalyzer(); Map classes = aa.parseInputJar(p.getInputJarPath()); - - aa.filter(classes, p.getInclusions(), p.getExclusions()); + + System.out.println(String.format("Classes loaded: %d", classes.size())); + + aa.filter(classes, p.getFilter()); + + System.out.println(String.format("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.getExclusions()); + src_gen.generateSource(dst_src_dir, classes, p.getFilter()); // dump the stubbed jar StubGenerator stub_gen = new StubGenerator(); File dst_jar = new File(p.getOutputJarPath()); - stub_gen.generateStubbedJar(dst_jar, classes, p.getExclusions()); + stub_gen.generateStubbedJar(dst_jar, classes, p.getFilter()); } } diff --git a/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java b/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java index 3eb19d613..461a25f13 100644 --- a/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java +++ b/tools/mkstubs/src/com/android/mkstubs/SourceGenerator.java @@ -26,7 +26,6 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; -import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -41,7 +40,7 @@ class SourceGenerator { */ public void generateSource(File baseDir, Map classes, - List exclusions) throws IOException { + Filter filter) throws IOException { for (Entry entry : classes.entrySet()) { ClassReader cr = entry.getValue(); @@ -51,7 +50,7 @@ class SourceGenerator { FileWriter fw = null; try { fw = createWriter(baseDir, name); - visitClassSource(fw, cr, exclusions); + visitClassSource(fw, cr, filter); } finally { fw.close(); } @@ -79,12 +78,12 @@ class SourceGenerator { * Generate a source equivalent to the stubbed version of the class reader, * minus all exclusions */ - void visitClassSource(Writer fw, ClassReader cr, List exclusions) { + void visitClassSource(Writer fw, ClassReader cr, Filter filter) { System.out.println("Dump " + cr.getClassName()); ClassVisitor javaWriter = new ClassSourcer(new Output(fw)); - ClassVisitor filter = new FilterClassAdapter(javaWriter, exclusions); - cr.accept(filter, 0 /*flags*/); + ClassVisitor classFilter = new FilterClassAdapter(javaWriter, filter); + cr.accept(classFilter, 0 /*flags*/); } } diff --git a/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java b/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java index 79855acb0..0321dc325 100644 --- a/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java +++ b/tools/mkstubs/src/com/android/mkstubs/StubGenerator.java @@ -25,7 +25,6 @@ import org.objectweb.asm.ClassWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; @@ -43,14 +42,14 @@ class StubGenerator { */ public void generateStubbedJar(File destJar, Map classes, - List exclusions) throws IOException { + Filter filter) throws IOException { TreeMap all = new TreeMap(); for (Entry entry : classes.entrySet()) { ClassReader cr = entry.getValue(); - byte[] b = visitClassStubber(cr, exclusions); + byte[] b = visitClassStubber(cr, filter); String name = classNameToEntryPath(cr.getClassName()); all.put(name, b); } @@ -88,7 +87,7 @@ class StubGenerator { jar.close(); } - byte[] visitClassStubber(ClassReader cr, List exclusions) { + byte[] visitClassStubber(ClassReader cr, Filter filter) { System.out.println("Stub " + cr.getClassName()); // Rewrite the new class from scratch, without reusing the constant pool from the @@ -96,8 +95,8 @@ class StubGenerator { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor stubWriter = new ClassStubber(cw); - ClassVisitor filter = new FilterClassAdapter(stubWriter, exclusions); - cr.accept(filter, 0 /*flags*/); + ClassVisitor classFilter = new FilterClassAdapter(stubWriter, filter); + cr.accept(classFilter, 0 /*flags*/); return cw.toByteArray(); } } diff --git a/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java b/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java index c413d1241..5b1f3a98e 100644 --- a/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java +++ b/tools/mkstubs/tests/com/android/mkstubs/SourceGeneratorTest.java @@ -24,7 +24,6 @@ import org.junit.Test; import org.objectweb.asm.ClassReader; import java.io.StringWriter; -import java.util.ArrayList; /** * @@ -48,7 +47,7 @@ public class SourceGeneratorTest { StringWriter sw = new StringWriter(); ClassReader cr = new ClassReader("data/TestBaseClass"); - mGen.visitClassSource(sw, cr, new ArrayList()); + mGen.visitClassSource(sw, cr, new Filter()); String s = sw.toString(); Assert.assertNotNull(s);