qdrzwd / dexmaker

Automatically exported from code.google.com/p/dexmaker
0 stars 0 forks source link

ProxyBuilder: Dex verification errors in logcat for private and package-visible methods #29

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?

public class SimpleClass {
}

public class Test extends Instrumentation {
  public void testSimpleProxy() throws IOException {
    ProxyBuilder.forClass(SimpleClass.class)
        .dexCache(getInstrumentation().getTargetContext().getDir("dx", Context.MODE_PRIVATE))
        .handler(new SomeInvocationHandler())
        .build();
  }
}

What is the expected output? What do you see instead?

Using adb logcat, I'd expect no errors. The logs will, however, include errors 
like:

D/dalvikvm( 4555): DEX prep '/data/data/test/app_dx/Generated-360119027.jar': 
unzip in 0ms, rewrite 58ms
I/dalvikvm( 4555): DexOpt: illegal method access (call 
Ljava/lang/Object;.internalClone (Ljava/lang/Cloneable;)Ljava/lang/Object; from 
LSimpleClass_Proxy;)
I/dalvikvm( 4555): Could not find method test.SimpleClass.internalClone, 
referenced from method SimpleClass_Proxy.internalClone
W/dalvikvm( 4555): VFY: unable to resolve virtual method 15: 
Ltest/SimpleClass;.internalClone (Ljava/lang/Cloneable;)Ljava/lang/Object;
D/dalvikvm( 4555): VFY: replacing opcode 0x6f at 0x0019
I/dalvikvm( 4555): DexOpt: illegal method access (call 
Ljava/lang/Object;.internalClone (Ljava/lang/Cloneable;)Ljava/lang/Object; from 
LSimpleClass_Proxy;)
I/dalvikvm( 4555): Could not find method test.SimpleClass.internalClone, 
referenced from method SimpleClass_Proxy.super$internalClone$java_lang_Object
W/dalvikvm( 4555): VFY: unable to resolve virtual method 15: 
Ltest/SimpleClass;.internalClone (Ljava/lang/Cloneable;)Ljava/lang/Object;
D/dalvikvm( 4555): VFY: replacing opcode 0x6f at 0x0000

What's more, these errors will be repeated for every private or package-visible 
method on the proxied class (or its superclasses). The ".internalClone" method 
listed here (and for every created proxy) is a private method defined on 
java.lang.Object, so is reported for every mock and proxy.

Please provide any additional information below.

I don't think this actually poses a functional problem, but I wanted to report 
it in case it can be easily fixed. These errors obviously become quite verbose 
and can get in the way of reading logcat.

The cause is the code generated in ProxyBuilder, which follows the prototype:

             *     public int doSomething(Bar param0, int param1) {
             *         if ($__handler == null) {
             *             return super.doSomething(param0, param1);
             *         }
             *         return __handler.invoke(this, __methodArray[4],
             *                 new Object[] { param0, Integer.valueOf(param1) });
             *     }

If the "doSomething" method is private or package-visible, then the call to 
super.doSomething is inaccessible from the generated proxy class. VFY spots 
this and removes the super call.

Is it possible to remove the proxy method altogether for private methods? I may 
be missing something, but I can't see how these should ever be called. DexMaker 
Issue 24 (https://code.google.com/p/dexmaker/issues/detail?id=24) appears to be 
a patch to do just this. I don't think the patch is quite right, however, as it 
would prevent package-visible methods from being proxied/mocked as well.

For package-visible methods, we do need the proxy method, but perhaps the 
"handler==null" case could just be an exception. This is a form of the general 
problem that ProxyBuilder has with package-visible classes.

Original issue reported on code.google.com by i...@google.com on 15 Oct 2013 at 3:12