gpt4 book ai didi

android - 使用错误调用操作码的 Dalvik 转换

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:05:36 25 4
gpt4 key购买 nike

我在使用 dalvik dex 转换器和它用来调用方法的操作码时遇到了问题。基本上我在类中定义了一个 private final 方法,在调用它时,dx 没有生成 invoke-direct 操作码,而是生成了 invoke-super。因为它是私有(private)方法,父类(super class)中不存在该方法,所以我在设备上遇到了 VFY 违规。我能够追踪到触发此事件的确切场景,并且它似乎发生在以下时间:

  1. 使用 JaCoCo 对类进行检测,以及
  2. 使用 --target 1.6 编译的类

如果满足这两个条件,生成的 dex 类将具有 invoke-super 而不是 invoke-direct。如果我禁用 JaCoCo 或者如果我使用 --target 1.5 进行编译,它会使用正确的 invoke-direct 操作码。

在查看 javap 反汇编类代码时,我可以看到是什么导致 dx 假设为 super 而不是 direct:

未检测,为 1.6 编译:

$ javap -d com.example.ClassName | grep waitForConnectivity
159: invokespecial #115; //Method waitForConnectivity:()V
$ dexdump -d classes.dex | grep waitForConnectivity
147ad8: 7010 6042 0200 |001e: invoke-direct {v2}, Lcom/example/ClassName;.waitForConnectivity:()V // method@4260

针对 1.5(--target 1.5)进行检测、编译:

$ javap -d com.example.ClassName | grep waitForConnectivity
235: invokespecial #115; //Method waitForConnectivity:()V
$ dexdump -d classes.dex | grep waitForConnectivity
149d4c: 7010 9242 0400 |0018: invoke-direct {v4}, Lcom/example/ClassName;.waitForConnectivity:()V // method@4292

为 1.6 编译:

$ javap -d com.example.ClassName | grep waitForConnectivity
235: invokespecial #115; //Method com/example/ClassName.waitForConnectivity:()V
$ dexdump -d classes.dex | grep waitForConnectivity
149d4c: 6f10 9242 0400 |0018: invoke-super {v4}, Lcom/example/ClassName;.waitForConnectivity:()V // method@4292

因此不同之处在于编译后的 .class 文件已经编译了引用 this 类的完全限定类名的 java 字节码(注意“//方法 waitForConnectivity:()V"与 "//Method com/example/ClassName.waitForConnectivity:()V")。似乎 dx 自动假设如果方法名是完全限定的,它必须使用 invoke-super,但如果不是限定的,它使用 invoke-direct

我的问题是:

  1. 这是 Android 的 dx 中的错误,还是 JaCoCo 中的错误?
  2. 如何避免这种情况,以便 JaCoCo 检测的类可以在我的自动化测试构建中正常工作?

我目前的解决方法是拥有一个 Maven“jacoco”配置文件,并在其中覆盖 ${java.version} 属性以将其从默认的“1.6”更改为“1.5”。有没有更好的解决方案?

最佳答案

dx 用来确定是否发出 invoke-superinvoke-direct 的规则之一是它是否相信方法调用正在与打电话的人在同一类(class)上制作。请参阅源代码中的 RopperMachine.java,大约在第 912 行,包含在此处以供引用:

        case ByteOps.INVOKESPECIAL: {
/*
* Determine whether the opcode should be
* INVOKE_DIRECT or INVOKE_SUPER. See vmspec-2 section 6
* on "invokespecial" as well as section 4.8.2 (7th
* bullet point) for the gory details.
*/
CstMethodRef ref = (CstMethodRef) cst;
if (ref.isInstanceInit() ||
(ref.getDefiningClass() == method.getDefiningClass()) ||
!method.getAccSuper()) {
return RegOps.INVOKE_DIRECT;
}
return RegOps.INVOKE_SUPER;

看到被错误转换的类的更完整的转储会很有趣。我认为您从 javap 中看到的可能不是现实的完整图景。请注意,dx 本身内置了一个 .class 文件转储器,它提供了比 javap 更多的细节。将其作为 dx --dump --bytes path/to/Name.class 调用。

关于android - 使用错误调用操作码的 Dalvik 转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17603192/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com