use of org.objectweb.asm.ClassReader in project android_frameworks_base by ParanoidAndroid.
the class DelegateClassAdapterTest method testConstructorsNotSupported.
/**
* {@link DelegateMethodAdapter2} does not support overriding constructors yet,
* so this should fail with an {@link UnsupportedOperationException}.
*
* Although not tested here, the message of the exception should contain the
* constructor signature.
*/
@Test(expected = UnsupportedOperationException.class)
public void testConstructorsNotSupported() throws IOException {
ClassWriter cw = new ClassWriter(0);
String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
HashSet<String> delegateMethods = new HashSet<String>();
delegateMethods.add("<init>");
DelegateClassAdapter cv = new DelegateClassAdapter(mLog, cw, internalClassName, delegateMethods);
ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
cr.accept(cv, 0);
}
use of org.objectweb.asm.ClassReader in project android_frameworks_base by ParanoidAndroid.
the class DelegateClassAdapterTest method testDelegateInner.
@Test
public void testDelegateInner() throws Throwable {
// We'll delegate the "get" method of both the inner and outer class.
HashSet<String> delegateMethods = new HashSet<String>();
delegateMethods.add("get");
delegateMethods.add("privateMethod");
// Generate the delegate for the outer class.
ClassWriter cwOuter = new ClassWriter(0);
String outerClassName = OUTER_CLASS_NAME.replace('.', '/');
DelegateClassAdapter cvOuter = new DelegateClassAdapter(mLog, cwOuter, outerClassName, delegateMethods);
ClassReader cr = new ClassReader(OUTER_CLASS_NAME);
cr.accept(cvOuter, 0);
// Generate the delegate for the inner class.
ClassWriter cwInner = new ClassWriter(0);
String innerClassName = INNER_CLASS_NAME.replace('.', '/');
DelegateClassAdapter cvInner = new DelegateClassAdapter(mLog, cwInner, innerClassName, delegateMethods);
cr = new ClassReader(INNER_CLASS_NAME);
cr.accept(cvInner, 0);
// Load the generated classes in a different class loader and try them
ClassLoader2 cl2 = null;
try {
cl2 = new ClassLoader2() {
@Override
public void testModifiedInstance() throws Exception {
// Check the outer class
Class<?> outerClazz2 = loadClass(OUTER_CLASS_NAME);
Object o2 = outerClazz2.newInstance();
assertNotNull(o2);
// The original Outer.get returns 1+10+20,
// but the delegate makes it return 4+10+20
assertEquals(4 + 10 + 20, callGet(o2, 10, 20));
assertEquals(1 + 10 + 20, callGet_Original(o2, 10, 20));
// The original Outer has a private method that is
// delegated. We should be able to call both the delegate
// and the original (which is now public).
assertEquals("outerPrivateMethod", callMethod(o2, "privateMethod_Original", false));
// The original method is private, so by default we can't access it
boolean gotIllegalAccessException = false;
try {
callMethod(o2, "privateMethod", false);
} catch (IllegalAccessException e) {
gotIllegalAccessException = true;
}
assertTrue(gotIllegalAccessException);
// Try again, but now making it accessible
assertEquals("outerPrivate_Delegate", callMethod(o2, "privateMethod", true));
// Check the inner class. Since it's not a static inner class, we need
// to use the hidden constructor that takes the outer class as first parameter.
Class<?> innerClazz2 = loadClass(INNER_CLASS_NAME);
Constructor<?> innerCons = innerClazz2.getConstructor(new Class<?>[] { outerClazz2 });
Object i2 = innerCons.newInstance(new Object[] { o2 });
assertNotNull(i2);
// The original Inner.get returns 3+10+20,
// but the delegate makes it return 6+10+20
assertEquals(6 + 10 + 20, callGet(i2, 10, 20));
assertEquals(3 + 10 + 20, callGet_Original(i2, 10, 20));
}
};
cl2.add(OUTER_CLASS_NAME, cwOuter.toByteArray());
cl2.add(INNER_CLASS_NAME, cwInner.toByteArray());
cl2.testModifiedInstance();
} catch (Throwable t) {
throw dumpGeneratedClass(t, cl2);
}
}
use of org.objectweb.asm.ClassReader in project android_frameworks_base by ParanoidAndroid.
the class DelegateClassAdapterTest method dumpGeneratedClass.
/**
* For debugging, it's useful to dump the content of the generated classes
* along with the exception that was generated.
*
* However to make it work you need to pull in the org.objectweb.asm.util.TraceClassVisitor
* class and associated utilities which are found in the ASM source jar. Since we don't
* want that dependency in the source code, we only put it manually for development and
* access the TraceClassVisitor via reflection if present.
*
* @param t The exception thrown by {@link ClassLoader2#testModifiedInstance()}
* @param cl2 The {@link ClassLoader2} instance with the generated bytecode.
* @return Either original {@code t} or a new wrapper {@link Throwable}
*/
private Throwable dumpGeneratedClass(Throwable t, ClassLoader2 cl2) {
try {
// For debugging, dump the bytecode of the class in case of unexpected error
// if we can find the TraceClassVisitor class.
Class<?> tcvClass = Class.forName("org.objectweb.asm.util.TraceClassVisitor");
StringBuilder sb = new StringBuilder();
sb.append('\n').append(t.getClass().getCanonicalName());
if (t.getMessage() != null) {
sb.append(": ").append(t.getMessage());
}
for (Entry<String, byte[]> entry : cl2.getByteCode()) {
String className = entry.getKey();
byte[] bytes = entry.getValue();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
// next 2 lines do: TraceClassVisitor tcv = new TraceClassVisitor(pw);
Constructor<?> cons = tcvClass.getConstructor(new Class<?>[] { pw.getClass() });
Object tcv = cons.newInstance(new Object[] { pw });
ClassReader cr2 = new ClassReader(bytes);
cr2.accept((ClassVisitor) tcv, 0);
sb.append("\nBytecode dump: <").append(className).append(">:\n").append(sw.toString());
}
// Re-throw exception with new message
RuntimeException ex = new RuntimeException(sb.toString(), t);
return ex;
} catch (Throwable ignore) {
// In case of problem, just throw the original exception as-is.
return t;
}
}
use of org.objectweb.asm.ClassReader in project android_frameworks_base by ParanoidAndroid.
the class DelegateClassAdapterTest method testNoOp.
/**
* Tests that a class not being modified still works.
*/
@SuppressWarnings("unchecked")
@Test
public void testNoOp() throws Throwable {
// create an instance of the class that will be modified
// (load the class in a distinct class loader so that we can trash its definition later)
ClassLoader cl1 = new ClassLoader(this.getClass().getClassLoader()) {
};
Class<ClassWithNative> clazz1 = (Class<ClassWithNative>) cl1.loadClass(NATIVE_CLASS_NAME);
ClassWithNative instance1 = clazz1.newInstance();
assertEquals(42, instance1.add(20, 22));
try {
instance1.callNativeInstance(10, 3.1415, new Object[0]);
fail("Test should have failed to invoke callTheNativeMethod [1]");
} catch (UnsatisfiedLinkError e) {
// This is expected to fail since the native method is not implemented.
}
// Now process it but tell the delegate to not modify any method
ClassWriter cw = new ClassWriter(0);
HashSet<String> delegateMethods = new HashSet<String>();
String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
DelegateClassAdapter cv = new DelegateClassAdapter(mLog, cw, internalClassName, delegateMethods);
ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
cr.accept(cv, 0);
// Load the generated class in a different class loader and try it again
ClassLoader2 cl2 = null;
try {
cl2 = new ClassLoader2() {
@Override
public void testModifiedInstance() throws Exception {
Class<?> clazz2 = loadClass(NATIVE_CLASS_NAME);
Object i2 = clazz2.newInstance();
assertNotNull(i2);
assertEquals(42, callAdd(i2, 20, 22));
try {
callCallNativeInstance(i2, 10, 3.1415, new Object[0]);
fail("Test should have failed to invoke callTheNativeMethod [2]");
} catch (InvocationTargetException e) {
// This is expected to fail since the native method has NOT been
// overridden here.
assertEquals(UnsatisfiedLinkError.class, e.getCause().getClass());
}
// Check that the native method does NOT have the new annotation
Method[] m = clazz2.getDeclaredMethods();
assertEquals("native_instance", m[2].getName());
assertTrue(Modifier.isNative(m[2].getModifiers()));
Annotation[] a = m[2].getAnnotations();
assertEquals(0, a.length);
}
};
cl2.add(NATIVE_CLASS_NAME, cw);
cl2.testModifiedInstance();
} catch (Throwable t) {
throw dumpGeneratedClass(t, cl2);
}
}
use of org.objectweb.asm.ClassReader in project android_frameworks_base by ParanoidAndroid.
the class AsmAnalyzerTest method testFindGlobs.
@Test
public void testFindGlobs() throws IOException, LogAbortException {
Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
// this matches classes, a package match returns nothing
found.clear();
mAa.findGlobs("mock_android.view", zipClasses, found);
assertArrayEquals(new String[] {}, found.keySet().toArray());
// a complex glob search. * is a search pattern that matches names, not dots
mAa.findGlobs("mock_android.*.*Group$*Layout*", zipClasses, found);
assertArrayEquals(new String[] { "mock_android.view.ViewGroup$LayoutParams", "mock_android.view.ViewGroup$MarginLayoutParams" }, found.keySet().toArray());
// a complex glob search. ** is a search pattern that matches names including dots
mAa.findGlobs("mock_android.**Group*", zipClasses, found);
assertArrayEquals(new String[] { "mock_android.view.ViewGroup", "mock_android.view.ViewGroup$LayoutParams", "mock_android.view.ViewGroup$MarginLayoutParams" }, found.keySet().toArray());
// matches a single class
found.clear();
mAa.findGlobs("mock_android.view.View", zipClasses, found);
assertArrayEquals(new String[] { "mock_android.view.View" }, found.keySet().toArray());
// matches everyting inside the given package but not sub-packages
found.clear();
mAa.findGlobs("mock_android.view.*", zipClasses, found);
assertArrayEquals(new String[] { "mock_android.view.View", "mock_android.view.ViewGroup", "mock_android.view.ViewGroup$LayoutParams", "mock_android.view.ViewGroup$MarginLayoutParams" }, found.keySet().toArray());
for (String key : found.keySet()) {
ClassReader value = found.get(key);
assertNotNull("No value for " + key, value);
assertEquals(key, AsmAnalyzer.classReaderToClassName(value));
}
}
Aggregations