Android加载SO库UnsatisfiedLinkError错误的缘由及解决方案

Android 应用开发者应该对 UnsatisfiedLinkError 这种类型的错误比较熟悉了,这个问题一直困扰着广大的开发者,那么有没有想过有可能你什么都没作错,也会出现这个问题呢?java

咱们在 Android 应用开发测试过程当中曾经碰到过这样的案例,apk 在某机型上安装完成以后运行即崩溃,报错 UnsatisfiedLinkError。android

 

java.lang.UnsatisfiedLinkError: Couldn’t load mobsec from loader dalvik.system.PathClassLoader.....findLibrary returned nullchrome

 

首先怀疑是在 apk 中相应的 libs\abi 目录下没有放置 libmobsec.so,然而检查发现这个 so 在全部的 libs\abi 下都有放置过,继续排查;shell

而后的想法是放置的 so 不是对应 abi 的,好比因为粗心在 armeabi 目录下放置了 x86 指令集的 so,致使在 armeabi 指令集手机上加载出错,这个也被排除掉;app

就在没有头绪的时候,想到 System.loadLibrary 函数加载 so 时,系统是从指定的路径下加载的,那么这个路径下 so 是否存在呢?函数

咱们知道应用的私有 Native library 目录 /data/data/packagename/lib 是一个符号连接,连接到 /data/app-lib/<package name> 目录,System.loadLibrary 是到这个目录去尝试加载 so 的。测试

adb shell 到这个路径下,使用命令 ls 查看,果真这个 libmobsec.so 是不存在的。那么是什么缘由致使的呢?spa

分析 Android 系统源码的实现,发现 /data/app-lib/<package name> 这个目录下的 so ,是在系统安装 apk 时从 apk 的 lib 目录下去抽取的。.net

在安装 app 时,Android package manager 代码须要分析当前手机支持的指令集并拷贝相关指令集的 so。从 Android2.X 到 Android6.0 系统,因为相继加入了 x8六、64位等指令集的支持,这一部分代码处理逻辑有很多变更,然而这个代码是存在逻辑缺陷的,存在遗漏拷贝的可能,致使在一些机型上并不必定保证全部的 so 都能被正确抽取到 /data/app-lib/<package name> 目录下,从而致使应用在加载 so 的时候出现 UnsatisfiedLinkError 这样的错误。code

已经有开发者意识到这个 bug,好比在 Chromium 的源代码的一段注释,说明了 Android package manager 中的问题:

     * PackageManager may fail to update shared library.
                    *
                    * Native library directory in an updated package is a symbolic link
                    * to a directory in /data/app-lib/<package name>, for example:
                    * /data/data/com.android.chrome/lib -> /data/app-lib/com.android.chrome[-1].
                    * When updating the application, the PackageManager create a new directory,
                    * e.g., /data/app-lib/com.android.chrome-2, and remove the old symlink and
                    * recreate one to the new directory. However, on some devices (e.g. Sony Xperia),
                    * the symlink was updated, but fails to extract new native libraries from
                    * the new apk.

  

在 Android 平台上加载本地库的危险性”这篇文章中提到了做者遇到一样的问题,并基于 Chromium 给出的一种权宜的解决办法:封装 System.loadLibrary 接口为 ReLinker 接口,若是发现没法正常加载 so,则获取 apk 路径并解压相应指令集的 so,而后尝试去加载。这种方案通过验证是能够显著减小 UnsatisfiedLinkError 错误的出现,下图为做者使用了 ReLinker 接口后的日上报 UnsatisfiedLinkError 错误数的变化趋势图。

ReLinker 接口如今已经集成到网易云捕的SDK中,使用方法以下:

ReLinker.loadLibrary(context, “mylibrary”);

来代替

System.loadLibrary(“mylibrary”);


参考连接:
apk安装过程及原理说明:http://blog.csdn.net/hdhd588/article/details/6739281
在Android平台上加载本地库的危险性:http://www.csdn.net/article/2015-11-10/2826182-the-perils-of-loading-native-libraries-on-android

更多资讯文章,可关注微博公众号:网易云捕

相关文章
相关标签/搜索