use of org.objectweb.asm.ClassWriter in project android_frameworks_base by DirtyUnicorns.
the class AsmGenerator method transform.
/**
* Transforms a class.
* <p/>
* There are 3 kind of transformations:
*
* 1- For "mock" dependencies classes, we want to remove all code from methods and replace
* by a stub. Native methods must be implemented with this stub too. Abstract methods are
* left intact. Modified classes must be overridable (non-private, non-final).
* Native methods must be made non-final, non-private.
*
* 2- For "keep" classes, we want to rewrite all native methods as indicated above.
* If a class has native methods, it must also be made non-private, non-final.
*
* Note that unfortunately static methods cannot be changed to non-static (since static and
* non-static are invoked differently.)
*/
byte[] transform(ClassReader cr, boolean stubNativesOnly) {
boolean hasNativeMethods = hasNativeMethods(cr);
// Get the class name, as an internal name (e.g. com/android/SomeClass$InnerClass)
String className = cr.getClassName();
String newName = transformName(className);
// transformName returns its input argument if there's no need to rename the class
if (!newName.equals(className)) {
mRenameCount++;
// This class is being renamed, so remove it from the list of classes not renamed.
mClassesNotRenamed.remove(className);
}
mLog.debug("Transform %s%s%s%s", className, newName.equals(className) ? "" : " (renamed to " + newName + ")", hasNativeMethods ? " -- has natives" : "", stubNativesOnly ? " -- stub natives only" : "");
// Rewrite the new class from scratch, without reusing the constant pool from the
// original class reader.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = cw;
// FIXME Generify
if ("android/content/res/Resources".equals(className)) {
cv = new FieldInjectorAdapter(cv);
}
if (mReplaceMethodCallsClasses.contains(className)) {
cv = new ReplaceMethodCallsAdapter(cv, className);
}
cv = new RefactorClassAdapter(cv, mRefactorClasses);
if (!newName.equals(className)) {
cv = new RenameClassAdapter(cv, className, newName);
}
String binaryNewName = newName.replace('/', '.');
if (mInjectedMethodsMap.keySet().contains(binaryNewName)) {
cv = new InjectMethodsAdapter(cv, mInjectedMethodsMap.get(binaryNewName));
}
cv = new TransformClassAdapter(mLog, mStubMethods, mDeleteReturns.get(className), newName, cv, stubNativesOnly);
Set<String> delegateMethods = mDelegateMethods.get(className);
if (delegateMethods != null && !delegateMethods.isEmpty()) {
// known to have no native methods, just skip this step.
if (hasNativeMethods || !(delegateMethods.size() == 1 && delegateMethods.contains(DelegateClassAdapter.ALL_NATIVES))) {
cv = new DelegateClassAdapter(mLog, cv, className, delegateMethods);
}
}
Set<String> promoteFields = mPromotedFields.get(className);
if (promoteFields != null && !promoteFields.isEmpty()) {
cv = new PromoteFieldClassAdapter(cv, promoteFields);
}
cr.accept(cv, 0);
return cw.toByteArray();
}
use of org.objectweb.asm.ClassWriter in project android_frameworks_base by DirtyUnicorns.
the class StubMethodAdapterTest method testBoolean.
/**
* @param methodPredicate tests if the method should be replaced
*/
private void testBoolean(BiPredicate<String, Type> methodPredicate, Consumer<Boolean> assertion, String methodName) throws Exception {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// Always rename the class to avoid conflict with the original class.
String newClassName = STUB_CLASS_NAME + '_';
new ClassReader(STUB_CLASS_NAME).accept(new ClassAdapter(newClassName, writer, methodPredicate), 0);
MyClassLoader myClassLoader = new MyClassLoader(newClassName, writer.toByteArray());
Class<?> aClass = myClassLoader.loadClass(newClassName);
assertTrue("StubClass not loaded by the classloader. Likely a bug in the test.", myClassLoader.findClassCalled);
Method method = aClass.getMethod(methodName);
Object o = aClass.newInstance();
assertion.accept((Boolean) method.invoke(o));
}
use of org.objectweb.asm.ClassWriter in project Minechem by iopleke.
the class MinechemTransformer method injectBytes.
private byte[] injectBytes(Method method, InstructionNode instructionNode, byte[] data) {
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(data);
classReader.accept(classNode, ClassReader.EXPAND_FRAMES);
MethodNode methodNode = getMethodByName(classNode, method);
AbstractInsnNode pos = findInstructionNode(instructionNode, methodNode);
if (instructionNode.replace) {
methodNode.instructions.insertBefore(pos, instructionNode.getInsnList());
methodNode.instructions.remove(pos);
} else {
methodNode.instructions.insertBefore(pos, instructionNode.getInsnList());
}
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(writer);
return writer.toByteArray();
}
use of org.objectweb.asm.ClassWriter in project android_frameworks_base by AOSPA.
the class DelegateClassAdapterTest method testDelegateNative.
@Test
public void testDelegateNative() throws Throwable {
ClassWriter cw = new ClassWriter(0);
String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
HashSet<String> delegateMethods = new HashSet<>();
delegateMethods.add(DelegateClassAdapter.ALL_NATIVES);
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
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);
// Use reflection to access inner methods
assertEquals(42, callAdd(i2, 20, 22));
Object[] objResult = new Object[] { null };
int result = callCallNativeInstance(i2, 10, 3.1415, objResult);
assertEquals((int) (10 + 3.1415), result);
assertSame(i2, objResult[0]);
// Check that the native method now has the new annotation and is not native
Method[] m = clazz2.getDeclaredMethods();
Method nativeInstanceMethod = null;
for (Method method : m) {
if ("native_instance".equals(method.getName())) {
nativeInstanceMethod = method;
break;
}
}
assertNotNull(nativeInstanceMethod);
assertFalse(Modifier.isNative(nativeInstanceMethod.getModifiers()));
Annotation[] a = nativeInstanceMethod.getAnnotations();
assertEquals("LayoutlibDelegate", a[0].annotationType().getSimpleName());
}
};
cl2.add(NATIVE_CLASS_NAME, cw);
cl2.testModifiedInstance();
} catch (Throwable t) {
throw dumpGeneratedClass(t, cl2);
}
}
use of org.objectweb.asm.ClassWriter in project android_frameworks_base by AOSPA.
the class DelegateClassAdapterTest method testNoOp.
/**
* Tests that a class not being modified still works.
*/
@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()) {
};
@SuppressWarnings("unchecked") 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 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();
Method nativeInstanceMethod = null;
for (Method method : m) {
if ("native_instance".equals(method.getName())) {
nativeInstanceMethod = method;
break;
}
}
assertNotNull(nativeInstanceMethod);
assertTrue(Modifier.isNative(nativeInstanceMethod.getModifiers()));
Annotation[] a = nativeInstanceMethod.getAnnotations();
assertEquals(0, a.length);
}
};
cl2.add(NATIVE_CLASS_NAME, cw);
cl2.testModifiedInstance();
} catch (Throwable t) {
throw dumpGeneratedClass(t, cl2);
}
}
Aggregations