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:
committed by
The Android Open Source Project
parent
b4432f4dea
commit
a4335fbe02
@@ -146,20 +146,15 @@ public class Main {
|
||||
|
||||
aa.filter(classes, p.getInclusions(), p.getExclusions());
|
||||
|
||||
AsmGenerator gen = new AsmGenerator();
|
||||
|
||||
// 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();
|
||||
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();
|
||||
File dst_jar = new File(p.getOutputJarPath());
|
||||
stub_gen.generateStubbedJar(dst_jar, classes, p.getExclusions());
|
||||
}
|
||||
|
||||
/** @deprecated debug only */
|
||||
private void displayClasses(Map<String, ClassReader> classes) {
|
||||
for(String className : classes.keySet()) {
|
||||
System.out.println("Found " + className);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.mkstubs;
|
||||
|
||||
import com.android.mkstubs.sourcer.JavaSourcer;
|
||||
import com.android.mkstubs.sourcer.ClassSourcer;
|
||||
import com.android.mkstubs.sourcer.Output;
|
||||
|
||||
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.
|
||||
@@ -51,7 +51,7 @@ class AsmGenerator {
|
||||
FileWriter fw = null;
|
||||
try {
|
||||
fw = createWriter(baseDir, name);
|
||||
dumpClass(fw, cr, exclusions);
|
||||
visitClassSource(fw, cr, exclusions);
|
||||
} finally {
|
||||
fw.close();
|
||||
}
|
||||
@@ -79,10 +79,10 @@ class AsmGenerator {
|
||||
* Generate a source equivalent to the stubbed version of the class reader,
|
||||
* 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());
|
||||
|
||||
ClassVisitor javaWriter = new JavaSourcer(new Output(fw));
|
||||
ClassVisitor javaWriter = new ClassSourcer(new Output(fw));
|
||||
ClassVisitor filter = new FilterClassAdapter(javaWriter, exclusions);
|
||||
cr.accept(filter, 0 /*flags*/);
|
||||
}
|
||||
103
tools/mkstubs/src/com/android/mkstubs/StubGenerator.java
Normal file
103
tools/mkstubs/src/com/android/mkstubs/StubGenerator.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,13 @@ import org.objectweb.asm.signature.SignatureReader;
|
||||
/**
|
||||
* A class visitor that rewrites a java source
|
||||
*/
|
||||
public class JavaSourcer implements ClassVisitor {
|
||||
public class ClassSourcer implements ClassVisitor {
|
||||
|
||||
private final Output mOutput;
|
||||
private final AccessSourcer mAccessSourcer;
|
||||
private String mClassName;
|
||||
|
||||
public JavaSourcer(Output output) {
|
||||
public ClassSourcer(Output output) {
|
||||
mOutput = output;
|
||||
mAccessSourcer = new AccessSourcer(mOutput);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
179
tools/mkstubs/src/com/android/mkstubs/stubber/MethodStubber.java
Normal file
179
tools/mkstubs/src/com/android/mkstubs/stubber/MethodStubber.java
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -29,13 +29,13 @@ import java.util.ArrayList;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class AsmGeneratorTest {
|
||||
public class SourceGeneratorTest {
|
||||
|
||||
private AsmGenerator mGen;
|
||||
private SourceGenerator mGen;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mGen = new AsmGenerator();
|
||||
mGen = new SourceGenerator();
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -48,7 +48,7 @@ public class AsmGeneratorTest {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestBaseClass");
|
||||
|
||||
mGen.dumpClass(sw, cr, new ArrayList<String>());
|
||||
mGen.visitClassSource(sw, cr, new ArrayList<String>());
|
||||
|
||||
String s = sw.toString();
|
||||
Assert.assertNotNull(s);
|
||||
@@ -27,7 +27,7 @@ import java.io.StringWriter;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class JavaSourcerTest extends TestHelper {
|
||||
public class ClassSourcerTest extends TestHelper {
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
@@ -48,7 +48,7 @@ public class JavaSourcerTest extends TestHelper {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestBaseClass");
|
||||
|
||||
JavaSourcer jw = new JavaSourcer(new Output(sw));
|
||||
ClassSourcer jw = new ClassSourcer(new Output(sw));
|
||||
cr.accept(jw, 0);
|
||||
|
||||
assertSourceEquals(
|
||||
@@ -78,7 +78,7 @@ public class JavaSourcerTest extends TestHelper {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestInnerClass");
|
||||
|
||||
JavaSourcer jw = new JavaSourcer(new Output(sw));
|
||||
ClassSourcer jw = new ClassSourcer(new Output(sw));
|
||||
cr.accept(jw, 0);
|
||||
|
||||
assertSourceEquals(
|
||||
@@ -106,7 +106,7 @@ public class JavaSourcerTest extends TestHelper {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestTemplateClass");
|
||||
|
||||
JavaSourcer jw = new JavaSourcer(new Output(sw));
|
||||
ClassSourcer jw = new ClassSourcer(new Output(sw));
|
||||
cr.accept(jw, 0);
|
||||
|
||||
assertSourceEquals(
|
||||
Reference in New Issue
Block a user