Android 的 ROM 中正常的软件都是 apk 内包含有一个 classes.dex,但也有时会没有(比如 MIUI 等),却有很多 .odex 文件,相对于 apk 中的 .dex 文件而言,这个 .odex 有什么作用呢?

首先分析一下 apk 文件的安装过程。安装 apk 包,会在 /data/app 目录复制一份安装包,在 /data/dalvik-cache 目录放一个解压出来的 classes.dex,如果有 .so 文件,还要复制到对应的文件夹。但是,如果把一个 apk 分解为 apk + odex,情况就大大不同了,这时完全可以把 apk 内的 lib 文件夹和 classes.dex 文件删掉,然后签名,配合 odex 一起使用,当然 so 文件也不能丢。所以:

  • 正常的 apk 包 = 原包 + classes.dex + so
  • 分解后的apk 包 = 分解包 + odex + so

扩展阅读:应用的安装路径和过程

关于 .odex 文件

.odex 是 Android 上的应用程序 apk 中提取出来的文件,即将 apk 中的 classes.dex 文件通过 dex 优化过程将其优化生成一个 .odex 文件单独存放,原 apk 中的 classes.dex 文件可删除或保留。

这样做可以加快软件的启动速度,预先提取,减少对 RAM 的占用,因为没有 odex 的话,系统要从 apk 包中提取 dex 再运行。

odex 化

简单说,原本系统恢复出厂设置后第一次开机需要先提取 classes.dex 出来,而 odex 化就是现在你提前把它提取出来了,系统启动或者程序运行加快的原因也就在此。提取后可以把 apk 内的 .dex 删除,以达到节省空间的目的。如果不 odex,那么系统还是会自动提取 .dex,这时不仅 apk 内有 .dex,例如 /data/dalvik-cache 目录下也有 .dex,虽然 apk 内的 .dex 经过压缩了,但是两份 .dex 的总体积已经大于一份 odex 的体积了。

关于 dalvik-cache

当 Android 启动时,Dalvik VM 监视所有的程序(apk 文件)和框架,并且为他们创建一个依存关系树。Dalvik VM 通过这个依存关系树来为每个程序优化代码并存储在 Dalvik 缓存中。这样,所有程序在运行时都会使用优化过的代码。这就是当你刷一个新的 ROM 时,有时候第一次启动时间非常非常长的原因。当一个程序(或者框架库)发生变更,Dalvik VM 将会重新优化代码并且再次将其存在缓存中。在 /cache/dalvik-cache 是存放 system 上的程序生成的 dex 文件,而 /data/dalvik-cache 则是存放 /data/app 生成的 dex 文件。

扩展阅读:dalvik-cache 路径下的 dex 是什么?

deodex 化

deodex 化(无 odex 文件),是合并 .odex 和少 .dex 的 apk 为完整的 apk 文件的操作。

优点和缺点

odex 化后系统启动和程序运行速度大大提高,稳定性不变。因此推荐做 odex 化。不过 odex 也有缺点,比如 odex 化的 ROM 不方便 hack ROM,另外当升级某个被 odex 化的应用,这个应用会出现故障,最常见的就是 FC1

举例:一般来说官方 ROM 都是 odex 化的 ROM(含 .odex 文件),而定制 ROM 大部分都是 deodex 化的(无 odex 文件)。两者各有优点。官方 ROM 大部分每个 apk 对应一个 .odex 文件,而 deodex 化的 ROM 里面只有一个 apk,把 .odex 转换成 classes.dex 放到 apk 包里面了。所以 odex ROM 的 .apk + .odex = deodex 化 ROM 的 1 个 .apk(简单来说,就是一个合并的过程)

官方 odex 化的 ROM 除了加载和开机速度更快以外,另外是不能使用系统 apk 文件安装应用的,也就是说没有 .dex 文件的 apk 是无法正常安装的。如果反编译 apk 文件,一般也只能得到资源文件2,而且 odex 是根据当前系统生成的,只能在生成 odex 的系统中运行,这也是直接复制带 odex 的程序到其他 ROM 不能运行的原因。这样可以说是起到一定的保护作用,避免被肆意修改和使用,使其厂商保证一定的反盗版。

关于:

  • 怎么 odex 化?
  • 怎么 deodex 化?
  • Android 8.0 以上的 odex 化方法

暂不在本文讨论范围。

  1. 运行程序的时候弹出一个对话框,强制关闭(Force Close)。

  2. apk 相对容易反编译和修改,而 .odex 要还原为 .dex 则先要解包成 smali 才能生成 classes.dex,如果要再生成 odex,还要用 dexopt-wrapper。