设为首页 加入收藏

TOP

系统应用集成过程中的一些坑(四)
2019-09-01 23:27:04 】 浏览:98
Tags:系统 应用 集成 过程 一些
我只是稍微过了下,并没有详细看,因为我最后选择的是 ReLinker 方案,但也可以大体上说一说:

  • 遍历设备所有存放 so 文件的目录,如 system/lib, vendor/lib,缓存其中所有的 so 文件名。
  • 如果系统加载 so 文件失败时,则从缓存的所有 so 文件名列表中寻找是否有和当前要加载的 so 文件一致的,有则直接加载这个 so 文件。

原理大体上应该是这样,感兴趣可以自行去看一下。

那么,这两个 so 文件加载的开源库有什么用呢?看你是否有遇到过 so 文件加载异常了,我的应用场景在埋坑一节里细说。

埋坑

好了,理论基础都已经有了,那么接下去就是来埋坑了。

针对开头所遇到的 bug,其实原因归根结底就是没有加载到正确的 so 文件,比如程序需要加载的是 system/lib64 下的 so 文件,但运维人员只集成到 system/lib 中;甚至说,运维人员连 so 文件都忘记集成到 system/lib 下了。

另外,运维人员希望,可以有一种统一的集成方法,他不需要去考虑是否还要根据其他条件来判断他是否要集成到 system/lib 还是 system/lib64 还是两者都要。

那么,解决方案其实有两种,一是给他一个新的无需考虑场景的集成方式;二是代码层面做适配,动态去加载所缺失的或不能用的 so 文件。

方案一:系统应用集成方式

假设需要集成的应用包名:com.dasu.shuai,apk 文件名:dasu.apk

  1. 在 system/app 目录下新建子目录,命名能表示那个应用即可,如:dasu
  2. 将 dasu.apk push 到 system/app/dasu/ 目录下
  3. 在 system/app/dasu 目录下新建子目录:lib/arm,这个命名是固定的,这样系统才可以识别
  4. apk 编译打包时,可以删掉其他 CPU 架构的 so 文件,只保留 armeabi-v7a 即可(根据你们应用的用户设备场景为主)
  5. 解压 apk 文件,取出里面的 lib/armeabi-v7a 下的 so 文件,push 到 system/lib 或 system/app/dasu/lib/arm 都可以
  6. 重启(如果应用首次集成需重启,否则 packages.xml 中无该应用的任何信息)

以上方案是针对我们应用自己的用户群场景的集成方式,如果想要通用,最好注意一下步骤 3 和 4,上述的这两个步骤目的在于让系统将该应用的 primaryCpuAbi 属性识别成 armeabi-v7a,这样就无需编译多个不同架构的 so 文件,集成也只需集成到 system/lib 目录中即可。

系统在扫描到 lib/arm 有这个目录存在时,会将 app 的 primaryCpuAbi 设置成 armeabi-v7a,相对应的,如果是 lib/arm64,那么就设置成 arm64-v8a,这是在 api22 机子上测试的结果。

方案二:代码适配

清楚了 ReLinker 的原理后,其实只要修改其中一个小小的流程即可。当系统加载 so 文件异常,ReLinker 接手来继续寻找 so 文件时,进行到解压 apk 包遍历所有 so 文件时,如果有多个不同 CPU 架构的 so 文件,此时修改原本的以第一个遍历到的 so 文件的逻辑,将其修改成寻找与此时应用的 primaryCpuAbi 一致的架构目录下的 so 文件来使用。

我是两种方案都做了,如果运维能够按照正常步骤集成,那么 so 文件加载异常的概率应该就不会大,即使运维哪个步骤操作失误了,方案二也可以弥补。

后记

本来以为这样子的解决方案足够解决这个问题了,也达到了运维人员的需求了。但没想到,事后居然又发现了新的问题:

由于我们是使用 fresco 图片库的,所以我们 app 的 so 文件其实都是来自 fresco 的,但没想到,合作的厂商它们自己的 app 也是使用的 fresco,然后他们也需要集成 so 文件。

但由于都是作为系统应用集成,so 文件都是统一集成在同一个目录中,如 system/lib,那么我们使用的 fresco 的 so 文件肯定就跟他们的 so 文件冲突了,因为文件名都一致,最后集成的时候就只使用他们的 so 文件。

然后,我们使用的 fresco 版本还跟他们不一样,结果就导致了,使用他们的 so 文件,我们的 app 运行时仍旧会报:

java.lang.UnsatisfiedLinkError: No implementation found for long com.facebook.imagepipeline.memory.NativeMemoryChunk.nativeAllocate(int) (tried Java_com_facebook_imagepipeline_memory_NativeMemoryChunk_nativeAllocate and Java_com_facebook_imagepipeline_memory_NativeMemoryChunk_nativeAllocate__I)

那要确认不同版本的 fresco 的 so 文件究竟有哪些差异,也只能去期待 fresco 官网是否有给出相关的文章。一般来说,新版本应该能兼容旧版本才对,这也就意味着,我们使用的版本其实比合作方他们新,如果集成时,使用的是我们的 so 文件,双方应该就都没问题。但跟他们合作一起集成时,如何来判断谁使用的版本新,谁的旧?都不更新的吗?

毕竟人家是厂商,我们只是需求合作,我们弱势,那还是我们自己再来想解决方案吧。

原本的 ReLinker 方案只能解决 so 文件不存在,加载失败,或者 so 文件 abi 异常的问题,但解决不了,so 文件的版本更新问题。

如果真要从代码层面着手,也不是不行,每次加载 so 文件前,先手动去系统的 so 文件目录中,将即将要加载的 so 文件进行一次 md5 计算,程序中可以保存打包时使用的 so 文件的 md5 值,两者相互比较,来判断 so 文件对应的代码版本是否一致。但这样会导致正常的流程需要额外处理一些耗时工作,自行评估吧。

或者,让运维人员在集成时,干脆不要将 so 文件集成到 system/lib 目录中,直接集成到 system/app/{新建目录}/lib/arm/ 目录下,这样我们就只使用我们自己的 so 文件,不用去担心跟他们共用时,版本差异问题了。

参考资料

1.APK文件结构和安装过程

2.Android程序包管理(2)--使用adb install执行安装过程

3.Android 的 so 文件加载机制


大家好,我是 dasu,欢迎关注我的公众号(dasuAndroidTv),如果你觉得本篇内容有帮助到你,可以转载但记得要关注,要标明原文哦,谢谢支持~
dasuAndroidTv2.png

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

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目