DVM ART 内置APK 32 64 兼容

这篇文章,最基本的理论开始,最后讲遇到问题解决方法

第一部分:odex vdex art 文件

vdex

  • package 直接转化的 可执行二进制码 文件:
  • 第一次开机就会生成在/system/app/<packagename>/oat/ 下;
  • 在系统运行过程中,虚拟机将其 从 “/system/app” 下 copy 到 “/data/davilk-cache/” 下

odex

  • odex 是从vdex 这个文件中 提取了部分模块生成的一个新的 可执行二进制码 文件 , odex 从vdex 中提取后,vdex 的大小就减少了。
  • 第一次开机就会生成在/system/app/<packagename>/oat/ 下
    在系统运行过程中,虚拟机将其 从 “/system/app” 下 copy 到 “/data/davilk-cache/” 下
  • odex + vdex = apk 的全部源码

art

  • odex 进行优化 生成的 可执行二进制码 文件,主要是apk 启动的热点函数相关地址的记录,方便寻址相关;
  • 第一次开机不会生成在/system/app/<packagename>/oat/ 下,以后也不会;
  • odex 文件在运行时,虚拟机会计算函数调用频率,进行函数地址的修改;如果频率比较多,就最后在/data/davilk-cache/ 由虚拟机生成;生成art 文件后,/system/app 下的odex 和 vdex 会无效,即使你删除,apk也会正常运行
  • push 一个新的apk file 覆盖之前/system/app 下apk file ,会触发PKMS 扫描时下发force_dex flag ,强行生成新的vdex 文件 ,覆盖之前的vdex 文件,由于某种机制,这个新vdex 文件会copy到/data/dalvik-cache/下,于是art 文件也变化了。

第二部分:JVM DVM ART

JVM:JVM虚拟机运行的是java字节码。java -> java bytecode(class) -> java bytecode(jar)。
DVM:DVM虚拟机解析执行的dex字节码。java -> java bytecode(class) -> dalvik bytecode(dex)。
ART:ART虚拟机执行本地机器码。java -> java bytecode(class) -> dalvik bytecode(dex) -> optimized android runtime machine code(oat->art)。

Android--<-Android 4.4-DVM-->ART-->Android 5.0--ART->Android 7.1-> DVM(JIT)&ART---->now
ART所使用的AOT(Ahead-Of-Time)编译,在应用首次安装时,字节码预编译成机器码存在本地
DVM是典型的JIT(Just-In-Time),在此模式下,应用每次运行的时候,字节码都需要即时编译器转换为机器码再执行

DVM vs ART

第三部分 ART 的运作方式

ART 官方说明
ART 使用预先 (AOT) 编译,并且从 Android 7.0(代号 Nougat,简称 N)开始结合使用 AOT、即时 (JIT) 编译和配置文件引导型编译。所有这些编译模式的组合均可配置,我们将在本部分中对此进行介绍。例如,Pixel 设备配置了以下编译流程:

最初安装应用时不进行任何 AOT 编译。应用前几次运行时,系统会对其进行解译,并对经常执行的方法进行 JIT 编译。
当设备闲置和充电时,编译守护进程会运行,以便根据在应用前几次运行期间生成的配置文件对常用代码进行 AOT 编译。
下一次重新启动应用时将会使用配置文件引导型代码,并避免在运行时对已经过编译的方法进行 JIT 编译。在应用后续运行期间进行了 JIT 编译的方法将会被添加到配置文件中,然后编译守护进程将会对这些方法进行 AOT 编译。
ART 包括一个编译器(dex2oat 工具)和一个为启动 Zygote 而加载的运行时 (libart.so)。dex2oat 工具接受一个 APK 文件,并生成一个或多个编译工件文件,然后运行时将会加载这些文件。文件的个数、扩展名和名称会因版本而异,但在 Android O 版本中,将会生成以下文件:

* .vdex:其中包含 APK 的未压缩 DEX 代码,另外还有一些旨在加快验证速度的元数据。
    * .odex:其中包含 APK 中已经过 AOT 编译的方法代码。
    * .art (optional):其中包含 APK 中列出的某些字符串和类的 ART 内部表示,用于加快应用启动速度。

第四部分:运行机制

DVM运行时中,APK在安装的时候,安装服务PackageManagerService会通过守护进程installd调用一个工具 dexopt对打包在APK里面包含有Dex字节码的classes.dex进行优化,优化得到的文件保存在/data/dalvik-cache目录 中,并且以.odex为后缀名,表示这是一个优化过的Dex文件。

ART运行时中,APK在安装的时候,同样安装服务 PackageManager Service会通过守护进程installd调用另外一个工具dex2oat对打包在APK里面包含有Dex字节码进翻译。翻译后得到的是一个ELF格式的oat文件,这个oat文件同样是以.odex后缀结束,并且也是保存在/data/dalvik-cache目录中。

Android在首次启动和首次安装应用时,需要将字节码翻译成机器码,这样Android系统的启动速度将会大大减慢,如果没有预优化,APP的运行速度也会加上翻译所需要的时间。所以,这个翻译的工作需要转移到编译上面来,也就是所,在编译APK文件时,将会预先对APK进行翻译的优化,然后再打包到系统里面去,这样Android系统在首次启动时,就不再需要花费大量的时间去翻译APK的字节码。

第五部分:遇到问题

03-12 10:48:50.247 1381 1381 E AndroidRuntime: Process: com.android.settings, PID: 1381
03-12 10:48:50.247 1381 1381 E AndroidRuntime: java.lang.RuntimeException: Unable to instantiate application com.android.settings.SettingsApplication: java.lang.ClassNotFoundException: Didn’t find class “com.android.settings.SettingsApplication” on path: DexPathList[[zip file “/system/priv-app/Settings/Settings.apk”],nativeLibraryDirectories=[/system/priv-app/Settings/lib/arm64, /system/priv-app/Settings/Settings.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib, /system/lib, /vendor/lib]]

下面指令查看 系统安装的package信息
adb shell dumpsys package p > dumpsys_p

注意出错的apk:primaryCpuAbi=arm64-v8a,是64 bit apk , 因此寻找了32 bit的库

apk架构确定顺序:

  • 如果apk包中lib文件夹下有.so库,就根据这个.so库的架构模式,确定app的primaryCpuAbi的值
  • 对于system app, 如果没法通过第一步确定primaryCpuAbi的值,PKMS会根据/system/app/${APP_NAME}/lib和/system/app/${APP_NAME}/lib64这两个文件夹是否存在,来确定它的primaryCpuAbi的值
  • 对于还没有确定的app, 在最后还会将自己的primaryCpuAbi值与和他使用相同UID的package的值设成一样
  • 对于到这里还没有确认primaryCpuAbi的app,就会在启动进程时使用ro.product.cpu.abilist这个property的值的第一项作为它关联的ABI

解决方法:
基于android加载so文件的机制,我们可以采用一下几种方法来解决该问题

  • apk不使用系统的uid,自己新增一个具有系统权限的uid(比较麻烦)
  • 把我们的apk修改为64位的,将所有使用的32位so替换为64位(可能有些三方so不提供64位版本
  • 把所有32位库再封装一次,做成jar包,然后使用这些jar包。(需要自己封装)
    将所有32位库服务抽离出来,单独运行一个(或多个)进程。(需要提前确定好app的架构,不然需要重构app)
  • 在系统apk(例如:Settings)安装位置system/priv-app/xxx/目录下面建立一个lib/arm64文件夹.(利用apk架构确定顺序强制将系统apk变为64位)
  • 将系统apk编译 不剥离 dex 模式
    a.在apk对应的android.mk中LOCAL_DEX_PREOPT := nostripping
    b./device/xxx/xxx/BoardConfig.mk,DEX_PREOPT_DEFAULT := nostripping

其他问题,在实际的解决问题的时候要考虑系统签名,API 版本问题

REF:
https://www.cnblogs.com/blogs-of-lxl/p/11608115.html
https://zhuanlan.zhihu.com/p/104122672
https://www.jianshu.com/p/18a8a4e6af3f

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350