AI 146829: am: CL 146744 am: CL 146720 ADT Jar Stubber: generate stubbed jar.

This also reorganizes some source so it's 90% refactoring.
  There will be more filtering to do in another CL.
  Original author: raphael
  Merged from: //branches/cupcake/...
  Original author: android-build

Automated import of CL 146829
This commit is contained in:
Raphael Moll
2009-04-18 22:50:00 -07:00
committed by The Android Open Source Project
parent b4432f4dea
commit a4335fbe02
8 changed files with 390 additions and 27 deletions

View File

@@ -146,20 +146,15 @@ public class Main {
aa.filter(classes, p.getInclusions(), p.getExclusions()); aa.filter(classes, p.getInclusions(), p.getExclusions());
AsmGenerator gen = new AsmGenerator();
// dump as Java source files, mostly for debugging // dump as Java source files, mostly for debugging
File dst_src_dir = new File(p.getOutputJarPath() + File.separator + "sources"); SourceGenerator src_gen = new SourceGenerator();
File dst_src_dir = new File(p.getOutputJarPath() + "_sources");
dst_src_dir.mkdir(); dst_src_dir.mkdir();
gen.generateSource(dst_src_dir, classes, p.getExclusions()); src_gen.generateSource(dst_src_dir, classes, p.getExclusions());
} // dump the stubbed jar
StubGenerator stub_gen = new StubGenerator();
/** @deprecated debug only */ File dst_jar = new File(p.getOutputJarPath());
private void displayClasses(Map<String, ClassReader> classes) { stub_gen.generateStubbedJar(dst_jar, classes, p.getExclusions());
for(String className : classes.keySet()) {
System.out.println("Found " + className);
} }
} }
}

View File

@@ -16,7 +16,7 @@
package com.android.mkstubs; package com.android.mkstubs;
import com.android.mkstubs.sourcer.JavaSourcer; import com.android.mkstubs.sourcer.ClassSourcer;
import com.android.mkstubs.sourcer.Output; import com.android.mkstubs.sourcer.Output;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
@@ -33,7 +33,7 @@ import java.util.Map.Entry;
/** /**
* *
*/ */
class AsmGenerator { class SourceGenerator {
/** /**
* Generate source for the stubbed classes, mostly for debug purposes. * Generate source for the stubbed classes, mostly for debug purposes.
@@ -51,7 +51,7 @@ class AsmGenerator {
FileWriter fw = null; FileWriter fw = null;
try { try {
fw = createWriter(baseDir, name); fw = createWriter(baseDir, name);
dumpClass(fw, cr, exclusions); visitClassSource(fw, cr, exclusions);
} finally { } finally {
fw.close(); fw.close();
} }
@@ -79,10 +79,10 @@ class AsmGenerator {
* Generate a source equivalent to the stubbed version of the class reader, * Generate a source equivalent to the stubbed version of the class reader,
* minus all exclusions * minus all exclusions
*/ */
void dumpClass(Writer fw, ClassReader cr, List<String> exclusions) { void visitClassSource(Writer fw, ClassReader cr, List<String> exclusions) {
System.out.println("Dump " + cr.getClassName()); System.out.println("Dump " + cr.getClassName());
ClassVisitor javaWriter = new JavaSourcer(new Output(fw)); ClassVisitor javaWriter = new ClassSourcer(new Output(fw));
ClassVisitor filter = new FilterClassAdapter(javaWriter, exclusions); ClassVisitor filter = new FilterClassAdapter(javaWriter, exclusions);
cr.accept(filter, 0 /*flags*/); cr.accept(filter, 0 /*flags*/);
} }

View File

@@ -0,0 +1,103 @@
/*
* 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 com.android.mkstubs.stubber.ClassStubber;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
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;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
/**
*
*/
class StubGenerator {
/**
* Generate source for the stubbed classes, mostly for debug purposes.
* @throws IOException
*/
public void generateStubbedJar(File destJar,
Map<String, ClassReader> classes,
List<String> exclusions) throws IOException {
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
for (Entry<String, ClassReader> entry : classes.entrySet()) {
ClassReader cr = entry.getValue();
byte[] b = visitClassStubber(cr, exclusions);
String name = classNameToEntryPath(cr.getClassName());
all.put(name, b);
}
createJar(new FileOutputStream(destJar), all);
System.out.println(String.format("Wrote %s", destJar.getPath()));
}
/**
* Utility method that converts a fully qualified java name into a JAR entry path
* e.g. for the input "android.view.View" it returns "android/view/View.class"
*/
String classNameToEntryPath(String className) {
return className.replaceAll("\\.", "/").concat(".class");
}
/**
* Writes the JAR file.
*
* @param outStream The file output stream were to write the JAR.
* @param all The map of all classes to output.
* @throws IOException if an I/O error has occurred
*/
void createJar(FileOutputStream outStream, Map<String,byte[]> all) throws IOException {
JarOutputStream jar = new JarOutputStream(outStream);
for (Entry<String, byte[]> entry : all.entrySet()) {
String name = entry.getKey();
JarEntry jar_entry = new JarEntry(name);
jar.putNextEntry(jar_entry);
jar.write(entry.getValue());
jar.closeEntry();
}
jar.flush();
jar.close();
}
byte[] visitClassStubber(ClassReader cr, List<String> exclusions) {
System.out.println("Stub " + cr.getClassName());
// Rewrite the new class from scratch, without reusing the constant pool from the
// original class reader.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor stubWriter = new ClassStubber(cw);
ClassVisitor filter = new FilterClassAdapter(stubWriter, exclusions);
cr.accept(filter, 0 /*flags*/);
return cw.toByteArray();
}
}

View File

@@ -27,13 +27,13 @@ import org.objectweb.asm.signature.SignatureReader;
/** /**
* A class visitor that rewrites a java source * A class visitor that rewrites a java source
*/ */
public class JavaSourcer implements ClassVisitor { public class ClassSourcer implements ClassVisitor {
private final Output mOutput; private final Output mOutput;
private final AccessSourcer mAccessSourcer; private final AccessSourcer mAccessSourcer;
private String mClassName; private String mClassName;
public JavaSourcer(Output output) { public ClassSourcer(Output output) {
mOutput = output; mOutput = output;
mAccessSourcer = new AccessSourcer(mOutput); mAccessSourcer = new AccessSourcer(mOutput);
} }

View File

@@ -0,0 +1,86 @@
/*
* 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.stubber;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
/**
*
*/
public class ClassStubber extends ClassAdapter {
public ClassStubber(ClassVisitor cv) {
super(cv);
}
@Override
public void visit(int version, int access,
String name,
String signature,
String superName,
String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public void visitEnd() {
super.visitEnd();
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return super.visitAnnotation(desc, visible);
}
@Override
public void visitAttribute(Attribute attr) {
super.visitAttribute(attr);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions) {
MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodStubber(mw, access, name, desc, signature, exceptions);
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature,
Object value) {
return super.visitField(access, name, desc, signature, value);
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
super.visitInnerClass(name, outerName, innerName, access);
}
@Override
public void visitOuterClass(String owner, String name, String desc) {
super.visitOuterClass(owner, name, desc);
}
@Override
public void visitSource(String source, String debug) {
super.visitSource(source, debug);
}
}

View File

@@ -0,0 +1,179 @@
/*
* 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.stubber;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
*
*/
public class MethodStubber extends MethodAdapter {
public MethodStubber(MethodVisitor mw,
int access, String name, String desc, String signature, String[] exceptions) {
super(mw);
}
@Override
public void visitCode() {
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(36, l0);
mv.visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException");
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn("stub");
mv.visitMethodInsn(
Opcodes.INVOKESPECIAL, // opcode
"java/lang/RuntimeException", // owner
"<init>", // name
"(Ljava/lang/String;)V"); // desc
mv.visitInsn(Opcodes.ATHROW);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable(
"this", // name
"Lcom/android/mkstubs/stubber/MethodStubber;", // desc
null, // signature
l0, // label start
l1, // label end
0); // index
mv.visitMaxs(3, 1); // maxStack, maxLocals
}
@Override
public void visitEnd() {
super.visitEnd();
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return super.visitAnnotation(desc, visible);
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
return super.visitAnnotationDefault();
}
@Override
public void visitAttribute(Attribute attr) {
super.visitAttribute(attr);
}
@Override
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
return super.visitParameterAnnotation(parameter, desc, visible);
}
// -- stuff that gets skipped
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
// skip
}
@Override
public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
// skip
}
@Override
public void visitIincInsn(int var, int increment) {
// skip
}
@Override
public void visitInsn(int opcode) {
// skip
}
@Override
public void visitIntInsn(int opcode, int operand) {
// skip
}
@Override
public void visitJumpInsn(int opcode, Label label) {
// skip
}
@Override
public void visitLabel(Label label) {
// skip
}
@Override
public void visitLdcInsn(Object cst) {
// skip
}
@Override
public void visitLineNumber(int line, Label start) {
// skip
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
// skip
}
@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
// skip
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
// skip
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
// skip
}
@Override
public void visitMultiANewArrayInsn(String desc, int dims) {
// skip
}
@Override
public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
// skip
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
// skip
}
@Override
public void visitTypeInsn(int opcode, String type) {
// skip
}
@Override
public void visitVarInsn(int opcode, int var) {
// skip
}
}

View File

@@ -29,13 +29,13 @@ import java.util.ArrayList;
/** /**
* *
*/ */
public class AsmGeneratorTest { public class SourceGeneratorTest {
private AsmGenerator mGen; private SourceGenerator mGen;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mGen = new AsmGenerator(); mGen = new SourceGenerator();
} }
@After @After
@@ -48,7 +48,7 @@ public class AsmGeneratorTest {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
ClassReader cr = new ClassReader("data/TestBaseClass"); ClassReader cr = new ClassReader("data/TestBaseClass");
mGen.dumpClass(sw, cr, new ArrayList<String>()); mGen.visitClassSource(sw, cr, new ArrayList<String>());
String s = sw.toString(); String s = sw.toString();
Assert.assertNotNull(s); Assert.assertNotNull(s);

View File

@@ -27,7 +27,7 @@ import java.io.StringWriter;
/** /**
* *
*/ */
public class JavaSourcerTest extends TestHelper { public class ClassSourcerTest extends TestHelper {
/** /**
* @throws java.lang.Exception * @throws java.lang.Exception
@@ -48,7 +48,7 @@ public class JavaSourcerTest extends TestHelper {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
ClassReader cr = new ClassReader("data/TestBaseClass"); ClassReader cr = new ClassReader("data/TestBaseClass");
JavaSourcer jw = new JavaSourcer(new Output(sw)); ClassSourcer jw = new ClassSourcer(new Output(sw));
cr.accept(jw, 0); cr.accept(jw, 0);
assertSourceEquals( assertSourceEquals(
@@ -78,7 +78,7 @@ public class JavaSourcerTest extends TestHelper {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
ClassReader cr = new ClassReader("data/TestInnerClass"); ClassReader cr = new ClassReader("data/TestInnerClass");
JavaSourcer jw = new JavaSourcer(new Output(sw)); ClassSourcer jw = new ClassSourcer(new Output(sw));
cr.accept(jw, 0); cr.accept(jw, 0);
assertSourceEquals( assertSourceEquals(
@@ -106,7 +106,7 @@ public class JavaSourcerTest extends TestHelper {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
ClassReader cr = new ClassReader("data/TestTemplateClass"); ClassReader cr = new ClassReader("data/TestTemplateClass");
JavaSourcer jw = new JavaSourcer(new Output(sw)); ClassSourcer jw = new ClassSourcer(new Output(sw));
cr.accept(jw, 0); cr.accept(jw, 0);
assertSourceEquals( assertSourceEquals(