继承的方法是不是计入 Android 中的 Dex 方法限制?

Posted

技术标签:

【中文标题】继承的方法是不是计入 Android 中的 Dex 方法限制?【英文标题】:Do inherited methods count against the Dex method limit in Android?继承的方法是否计入 Android 中的 Dex 方法限制? 【发布时间】:2013-07-17 20:06:04 【问题描述】:

Dalvik 在单个 .dex 文件中可以拥有的方法数量有这个众所周知的限制(大约 65,536 个)。我的问题是继承(但不是覆盖)方法是否计入此限制。

为了具体化,假设我有:

public class Foo 
  public int foo() 
    return 0;
  


public class A extends Foo  
public class B extends Foo  
public class C extends Foo  

出于 65,536 种方法限制的目的,这算作添加一种方法还是添加 4 种方法? (或者,我想,按照他们的逻辑结论,这算作 1 个方法还是 52 个方法,考虑到 java.lang.Object 也带来了 12 个方法)。

作为背景,我有大量具有一些共性的生成类,而且我也遇到了方法限制,所以我想知道是否值得尝试将其中的一些抽象出来进入类层次结构以争取一些时间。

【问题讨论】:

既然您可以更改方法的可见性,那么需要计算所有这些方法不是很有意义吗? See here for dex format. retrodev 链接指向 dex 文件格式的预发布版本的可悲过时的逆向工程。尝试 source.android.com/devices/tech/dalvik/dex-format.html> 以获得更权威和最新的来源。 dex-format.html 上的 404 @JonShemitz:只需从 URL 栏中删除尾随的 >。他应该在那儿加个空格。 酷 - 谢谢。 source.android.com/devices/tech/dalvik/dex-format.html 工作。 【参考方案1】:

一个继承但未被覆盖的方法仅在被引用(调用)时才计入方法限制。

在您的示例中,假设您有以下代码

public class main 
    public static void main(String[] args) 
        Foo foo = new A();
        foo.foo();
    

在这种情况下,您指的是 Foo.foo(),由于显式定义,它已经有一个引用。假设这 5 个类是 dex 文件中唯一的类,那么您总共将有 2 个方法引用*。一个用于 main.main(String[]),一个用于 Foo.foo()。

相反,假设您有以下代码

public class main 
    public static void main(String[] args) 
        A a = new A();
        a.foo();

        B b = new B();
        b.foo();

        C c = new C();
        c.foo();
    

在这种情况下,由于实际引用了每个子类的 foo 方法,它们将计入您的方法限制。您的 dex 文件将包含 5 个方法引用*。

main.main(String[]) Foo.foo() A.foo() B.foo() C.foo()

* 这个计数不是很准确,它没有考虑在幕后添加到每个类的构造方法。每个构造函数都调用它的超类的构造函数,所以我们还有一个 Object 构造函数的引用,每种情况下总共有 6 个额外的方法引用,分别给出了 8 个和 11 个方法计数。


如果有疑问,您可以尝试各种场景并使用 baksmali 的原始转储功能来查看 dex 文件中的方法列表实际包含的内容。

例如

javac *.java
dx --dex --output=temp.dex *.class
baksmali -N -D temp.dump temp.dex

然后,在转储文件中,查找“method_id_item 部分”。这是 64k 限制适用的方法引用列表。

【讨论】:

构造函数不也算作方法引用吗?那么这不会增加示例中方法引用的数量吗? @nvrmnd,是的。这是一个好点。我会相应地更新答案。谢谢! .SO 文件或 JNI 代码中的方法是否计入此限制? 从 dex 的角度来看,JNI 方法没有什么特别之处,除了它具有“本机”访问标志且没有实现之外。所以是的,dex 文件中的方法 id 列表包括了 dex 文件中声明(或调用)的所有 jni 方法。

以上是关于继承的方法是不是计入 Android 中的 Dex 方法限制?的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )(代码片

解决Android单个dex文件不能超过65535个方法问题

Android 中的 .dex 文件是啥?

.dex 文件中的方法引用数超过 64K

Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmContinueOptimizati() 函数分析 )

.onAuthStateChanged 方法是不是计入 Firebase 身份验证验证?