设为首页 加入收藏

TOP

系统应用集成过程中的一些坑(三)
2019-09-01 23:27:04 】 浏览:97
Tags:系统 应用 集成 过程 一些
ml

这份配置文件在 data/system/ 目录下,不要小看这份文件,因为不管系统应用还是三方应用,安装过程中都会将其自身的基本信息写入这份文件中。所以,借助这份文件,可以获取到蛮多信息的。

比如,一般排查系统应用为什么启动不了,就可以借助这份文件。

碰到过这么一个问题,我们做的一些应用是没有界面的,就纯粹在后台干活。如果是三方,也许还可以通过手动去启动这个应用来查看相关日志,但偏偏还有些应用是设备开机时就自启的,所以最怕遇到的问题就是测试人员跟你说,这个应用在某个终端上起不来。

因为这时,不清楚这个应用到底是不是因为代码问题导致一直崩溃,起不来;还是因为根本就没安装成功;所以,遇到这类问题,第一点就是要先确认这一点,而确认这一点,就可以借助 packages.xml 这份配置文件了。

如果能够在这份 packages.xml 配置文件中找到应用的信息,那么说明安装成功了,接下去就往另一个方向排查问题了。

还有一种场景借助这份配置文件分析也是很有帮助的。

我们还遇到这种情况:

首先 system/app 下是系统应用,data/app 下是三方应用,但系统是允许 system/app 和 data/app 下存在相同包名的应用,因为允许系统应用进行升级操作,只是此时系统应用将变成三方应用权限。

某次,有反馈说,system/app 下已集成了最新版本的应用,但为什么,每次启动应用时,运行的都是旧版本。这时候怎么排查,就是根据 packages.xml 中这个应用的基本信息,它包括,这个应用的版本号,apk 的来源目录,so 文件的加载地址,所申请的权限等等。

有了这些信息,足够确认,此刻运行的应用是 data/app 下的 apk,还是 system/app 下的 apk。确认了之后,再进一步去排查。

4. System.load 和 System.loadlibrary

load()loadlibrary() 都是用来加载 so 文件的,区别仅在于 load() 接收的是绝对路径,比如 ”data/data/{包名}/lib/xxx.so“ 这样子,因为是绝对路径,所以最后跟着的是 so 文件全名,包括后缀名。

loadlibrary() 只需传入 so 文件去头截尾的名字就可以了,如 libblur.so,只需传入 blur 即可,内部会自动补全 so 文件可能存在的路径,以及补全 lib 前缀和 .so 后缀。

所以,下面要讲的,其实就是 loadlibrary() 加载 so 文件的流程。

因为之前碰到过这么个问题,有些不大理解:

我们的应用是系统应用,那么 so 文件也就是集成到 system/lib 或者 system/lib64 目录下,但不清楚,程序是根据什么决定是应该去 system/lib 目录下加载 so 文件,还是去 system/lib64 下加载,或者两处都会去?

所以,下个小节就是讲这个。

5. so 文件加载流程

这节是本篇的重点,打算亲自过下源码来梳理,但这样篇幅会特别长,基于此,就另起一篇来专门写从源码中梳理 so 文件的加载流程吧,这里就只给出链接和几点结论,感兴趣的可以去看看。

Android 的 so 文件加载机制

  • 一个应用在安装过程中,系统会经过一系列复杂的逻辑确定两个跟 so 文件加载相关的 app 属性值:nativeLibraryDirectories ,primaryCpuAbi ;
  • nativeLibraryDirectories 表示应用自身存放 so 文件的目录地址,影响着 so 文件的加载流程;
  • primaryCpuAbi 表示应用应该运行在哪种 abi 上,如(armeabi-v7a),它影响着应用是运行在 32 位还是 64 位的进程上,进而影响到寻找系统指定的 so 文件目录的流程;
  • 以上两个属性,在应用安装结束后,可在 data/system/packages.xml 中查看;
  • 当调用 System 的 loadLibrary() 加载 so 文件时,流程如下:
  • 先到 nativeLibraryDirectories 指向的目录中寻找,是否存在且可用的 so 文件,有则直接加载这里的 so 文件;
  • 上一步没找到的话,则根据当前进程如果是 32 位的,那么依次去 vendor/lib 和 system/lib 目录中寻找;
  • 同样,如果当前进程是 64 位的,那么依次去 vendor/lib64 和 system/lib64 目录中寻找;
  • 当前应用是运行在 32 位还是 64 位的进程上,取决于系统的 ro.zygote 属性和应用的 primaryCpuAbi 属性值,系统的 ro.zygote 可通过执行 getprop 命令查看;
  • 如果 ro.zygote 属性为 zygote64_32,那么应用启动时,会先在 ro.product.cpu.abilist64 列表中寻找是否支持 primaryCpuAbi 属性,有,则该应用运行在 64 位的进程上;
  • 如果上一步不支持,那么会在 ro.product.cpu.abilist32 列表中寻找是否支持 primaryCpuAbi 属性,有,则该应用运行在 32 位的进程上;
  • 如果 ro.zygote 属性为 zygote32_64,则上述两个步骤互换;
  • 如果应用的 primaryCpuAbi 属性为空,那么以 ro.product.cpu.abilist 列表中第一个 abi 值作为应用的 primaryCpuAbi;
  • 运行在 64 位的 abi 有:arm64-v8a,mips64,x86_64
  • 运行在 32 位的 abi 有:armeabi-v7a,armeabi,mips,x86
  • 通常支持 arm64-v8a 的 64 位设备,都会向下兼容支持 32 位的 abi 运行;
  • 但应用运行期间,不能混合着使用不同 abi 的 so 文件;
  • 比如,当应用运行在 64 位进程中时,无法使用 32 位 abi 的 so 文件,同样,应用运行在 32 位进程中时,也无法使用 64 位 abi 的 so 文件;

6. 三方库 ReLinker 和 Soloder

ReLinker 和 Soloder 都是用于解决一些 so 文件加载失败的场景,比如:

  • 嵌套的 so 文件加载异常,如程序引用了三方库,三方库又引用了三方库,各自库中又都存在 so 文件加载,有时候可能会导致 so 文件加载失败。
  • so 文件缺失导致加载异常,如程序的 so 文件在设备的 so 目录中不见了之类的异常。
  • 等等

它们的 Github 地址:

SoLoader:https://github.com/facebook/SoLoader

ReLinker:https://github.com/KeepSafe/ReLinker

ReLinker 的原理我有去源码梳理了一遍,大体上是这样:

  1. 先调用系统 System.loadlibrary() 加载 so 文件,如果成功,结束;
  2. 如果失败,则重新解压 apk 文件,解析其中的 lib 目录,遍历 so 文件,找到所需的 so 文件时,将其缓存一份至 data/data/{包名}/app-lib 目录下,调用 System.load() 加载这份 so 文件;
  3. 之后每次应用重启,仍旧先调用系统的 System.loadlibrary() 去尝试加载 so 文件,失败,如果 app-lib 下有缓存,且可用,则加载这个缓存的 so 文件,否则重新解压 apk,继续 2 步骤。
  • 当然,解压 apk 遍历 so 文件时,如果需要的 so 文件存在于不同的 CPU 架构目录中,并不加以区分,直接拿第一个遍历到的 so 文件。

SoLoder 的原理

首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇学习安卓开发[4] - 使用隐式Inten.. 下一篇安卓开发学习笔记(六):如何实..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目