Android加载SO库UnsatisfiedLinkError错误的原因及解决方案
Android 应用开发者应该对 UnsatisfiedLinkError 这种类型的错误比较熟悉了,这个问题一直困扰着广大的开发者,那么有没有想过有可能你什么都没做错,也会出现这个问题呢?
我们在 Android 应用开发测试过程中曾经碰到过这样的案例,apk 在某机型上安装完成之后运行即崩溃,报错 UnsatisfiedLinkError。
java.lang.UnsatisfiedLinkError: Couldn’t load mobsec from loader dalvik.system.PathClassLoader.....findLibrary returned null
首先怀疑是在 apk 中相应的 libs\abi 目录下没有放置 libmobsec.so,然而检查发现这个 so 在所有的 libs\abi 下都有放置过,继续排查;
然后的想法是放置的 so 不是对应 abi 的,比如由于粗心在 armeabi 目录下放置了 x86 指令集的 so,导致在 armeabi 指令集手机上加载出错,这个也被排除掉;
就在没有头绪的时候,想到 System.loadLibrary 函数加载 so 时,系统是从指定的路径下加载的,那么这个路径下 so 是否存在呢?
我们知道应用的私有 Native library 目录 /data/data/packagename/lib 是一个符号链接,链接到 /data/app-lib/<package name> 目录,System.loadLibrary 是到这个目录去尝试加载 so 的。
adb shell 到这个路径下,使用命令 ls 查看,果然这个 libmobsec.so 是不存在的。那么是什么原因导致的呢?
分析 Android 系统源码的实现,发现 /data/app-lib/<package name> 这个目录下的 so ,是在系统安装 apk 时从 apk 的 lib 目录下去抽取的。

在安装 app 时,Android package manager 代码需要分析当前手机支持的指令集并拷贝相关指令集的 so。从 Android2.X 到 Android6.0 系统,由于相继加入了 x86、64位等指令集的支持,这一部分代码处理逻辑有不少变动,然而这个代码是存在逻辑缺陷的,存在遗漏拷贝的可能,导致在一些机型上并不一定保证所有的 so 都能被正确抽取到 /data/app-lib/<package name> 目录下,从而导致应用在加载 so 的时候出现 UnsatisfiedLinkError 这样的错误。
已经有开发者意识到这个 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
更多资讯文章,可关注微博公众号:网易云捕
Android加载SO库UnsatisfiedLinkError错误的原因及解决方案的更多相关文章
- LoadLibrary加载动态库失败
[1]LoadLibrary加载动态库失败的可能原因以及解决方案: (1)dll动态库文件路径不对.此场景细分为以下几种情况: 1.1 文件路径的确错误.比如:本来欲加载的是A文件夹下的动态库a.dl ...
- android通过Jni加载so库遇到UnsatisfiedLinkError问题!!!
错误信息: java.lang.UnsatisfiedLinkError: hsl.p2pipcam.nativecaller.NativeCaller at hsl.p2pipcam.manager ...
- 【转载】cocos2dx 中 Android NDK 加载动态库的问题
原文地址:http://blog.csdn.net/sozell/article/details/10551309 cocos2dx 中 Android NDK 加载动态库的问题 闲聊 最近在接入各 ...
- lua加载动态库缺乏相应的系统库
错误信息: 使用lua测试lm2动态库时,加载时出现如下错误 jfyuan@jfy11-B85M-D2V:~/temp/service/soft/code/ginger_resty/cores/lm2 ...
- NDK jni 加载静态库
加载静态库到android,静态库的提供方式有2种, a. 通过源文件来编译静态库 b. 加载已经编译好的静态库 首先我们来看,通过源文件来编译静态库,工程目录如下 第一步:我们来看我们的jni目录, ...
- Linux下c函数dlopen实现加载动态库so文件代码举例
dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了. ...
- PostgreSql扩展Sql-动态加载共享库(C函数)
基于 psql (PostgreSQL) 10.4 pg_language表定义了函数实现所使用的语言.主要支持了C语言和SQL语句.一些可选的语言包括pl/pgsql.tcl和perl. ligan ...
- Xilinx SDSoc 加载opencv库
Xilinx SDSoc 加载opencv库需要下载两个文件 xfopencv 和 Revision Platform, Revision Platform需要和具体的开发板型号对应,我用的是zcu1 ...
- Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)【系列1】
Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)[系列1] Android在加载或者处理超大巨型图片 ...
随机推荐
- javaweb学习总结(十四)——JSP原理
一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写h ...
- CStringArray用法
CStringArray使用之前先设置数组尺寸SetSize,才能使用SetAt CStringArray m_strScrkRfid ; ...
- Linux内核--异常和中断的区别
相信大家都知道非常著名的两个名词:异常和中断,不过,你真的理解这两个名词在说什么吗?它们之间有什么区别呢? 1.中断 大家都知道,当我们在敲击键盘的同时就会产生中断 ...
- LeakCanary 中文使用说明
http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/ LeakCanary 中文使用说明 分享到:新浪微博微信 10 May 2015 Leak ...
- 转:Directshow开发的一些例子
DirectShow Filter 开发典型例子分析 --字幕叠加 (FilterTitleOverlay)1 本文分析一下<DirectShow开发指南>中的一个典型的Transform ...
- ES5 数组方法map
概述 map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组. 语法 array.map(callback[, thisArg]) 参数 callback 原数组中的元素经 ...
- C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]
文章摘要: 1. 通过简单DEMO.让读者理解Task和Task<T> 学习过程中,掌握async和await 2. 理解同步和异步的执行 3. Task.Factory.Start ...
- Fiddler高级技巧 - 映射路径到本地文件夹
适用场景: 你是前端开发人员,要开发一个小模块,需要用到线上的环境(账号.数据.跨域等),但你又没有权限往线上传文件 你是移动测试人员,需要将一组接口的返回结果替换为另一组,最简单的办法就是使用Fid ...
- Scala 深入浅出实战经典 第58讲:Scala中Abstract Types实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- 关于SQLServer2008数据如何导入SQL2005的解决办法,高版本数据导入低版本中。
最近需要把SqlServer2008 的数据库导入sqlserver2005 中.直接备份还原肯定不行.后来想到可以生成脚本执行sql语句,并选择数据可以一同进行执行. 点击右键--->任务-- ...