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在加载或者处理超大巨型图片 ...
随机推荐
- paip.php 与js 的相似性以及为什么它们这么烂还很流行。。
paip.php 与js 的相似性以及为什么它们这么烂还很流行.. php与js异常的流行,web 90%都被他们统治了.发现了他们有意思的一些共性.. 结构一番总结,得出了它们共有的特点.特性: = ...
- Python之Django【基础篇】
Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...
- dom4j 读取xml
package core.util; import java.io.File; import java.util.Iterator; import java.util.List; import org ...
- Win7下SQLite的简单使用
前言 SQLite 是一个软件库,实现了自给自足的.无服务器的.零配置的.事务性的 SQL 数据库引擎.SQLite 是在世界上最广泛部署的 SQL 数据库引擎.SQLite 源代码不受版权限制. 简 ...
- 【Android】android中Invalidate和postInvalidate的区别
Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用. Android提供了Inva ...
- 兼容iOS 10 资料整理
1.Notification(通知) 自从Notification被引入之后,苹果就不断的更新优化,但这些更新优化只是小打小闹,直至现在iOS 10开始真正的进行大改重构,这让开发者也体会到UserN ...
- Java 中的instanceof简单讲解
Java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例.instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例. 用法:resu ...
- 【OpenWRT】 Chaos Calmer 15.05 编译
进入正题,编译环境准备完毕后,下载源码 git clone git://git.coding.net/leop/openwrt.git 复制代码 复制dl包(可以加快初次编译速度,但非必须)链接:pa ...
- Codeforces Round #379 (Div. 2) D. Anton and Chess 水题
D. Anton and Chess 题目连接: http://codeforces.com/contest/734/problem/D Description Anton likes to play ...
- 互联网的寒冬来了,BAT都不社招了
一 总理上次来到创业街,是四个月,要不就是五个月前了. 之后,全国创业形势一路走红,锣鼓喧天鞭炮齐鸣.大众创业万众创新,颇有大炼钢铁亩产万斤之势,尤其在媒体上. 再之后,2015 进入下半年,风投圈的 ...