[持续更新]UnsatisfiedLinkError常见问题及解决方案
想必很多开发者和我们一样,遇到过许多UnsatisfiedLinkError的困难,着实令人头疼,现在总结一下,希望能帮助更多的人。
常见错误
- lib库不同目录下的SO文件参差不齐。
- lib库目录下的SO不符合相应的CPU架构。
- 64-bit下使用System.load加载SO:"lib_xyz.so" is 32-bit instead of 64-bit
- java代码混淆导致。
- 注册方式不对,或已经被其他类注册。
- empty/missing DT_HASH in "libxxxx.so" (built with --hash-style=gnu?)
出错现象及解决方案
lib库不同目录下的SO文件参差不齐。
发现很多APK包打出来,lib目录下同时带着armeabi、armeabi-v7a,但是armeabi目录下可能有3个SO,而armeabi-v7a下只有2个SO,更有甚者还有armeabi、armeabi-v7a、x86、x86_64、arm64-v8a全部都有,但是不同目录下的SO个数都不一样。
这样打出来的APK包,在安装的时候会让Android系统“很为难”,它搞不清到底该选择哪个SO来安装。有时可能会造成某个SO的漏安装,那么在APP运行的时候加载SO时就会出现异常了。
解决方案:
1、只保留lib下的一个目录足够(armeabi或armeabi-v7a保留一个),其他目录全部不用配置。
2、如果想继续多配置几个CPU架构的lib目录,那就全部配置齐全。实际上有时候很难做到,特别是当需要使用三方库的SO的时候,往往并不那么容易找的齐全。由于全部打齐全会对APK的体积有增加,所以还是推荐第一种方案。
lib库目录下的SO不符合相应的CPU架构。
同上面的问题差不多,有些APK包打出来,同时配置了armeabi和arm64-v8,但是却在arm64-v8放置了某个或多个armeabi版本的SO,那么在APP运行的时候就会报类似的错误:"lib_xyz.so" is 32-bit instead of 64-bit
64-bit下使用System.load加载SO:"lib_xyz.so" is 32-bit instead of 64-bit
Found an explanation: 64-bit Android can use 32-bit native libraries as a fallback,
only if System.loadlLibrary() can't find anything better in the default search path.
You get an UnsatisfiedLinkError if you force the system to load the 32-bit library using System.load() with the full library path.
So the first workaround is using System.loadLibrary() instead of System.load().
64-bit处理器可以向下兼容32-bit指令集,即可以运行32-bit动态库,所以APK包仍然可以只保留lib下的一个目录足够(armeabi或armeabi-v7a保留一个),其他目录全部不用配置。
有一种组合错误,就是APK的lib库打的参差不齐,又在64-bit下使用System.load加载SO。
有一个APP在MX5(android5.0.1)下出现了以下异常:
Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: "/data/data/com.xxx.pris/app_lib/libPDEEngine.so" is 32-bit instead of 64-bit
首先可以大致知道这是一个64位的机器,查看云捕展示的机器信息,确实是arm64-v8a。首先就是看APK的lib目录打的对不对,果然
armeabi下有12个SO,而armeabi-v7a下却只有11个SO。但是他们使用了云捕代码来尝试安全加载SO来降低UnsatisfiedLinkError的异常。
public static void loadLibrary(final Context context, final String library) {
if (context == null) {
throw new IllegalArgumentException("Given context is null");
}
if (TextUtils.isEmpty(library)) {
throw new IllegalArgumentException("Given library is either null or empty");
}
try {
System.loadLibrary(library);
return;
} catch (final UnsatisfiedLinkError ignored) {
// :-(
CrashHandler.leaveBreadcrumb("ReLinker: System.loadLibrary failed");
}
final File workaroundFile = getWorkaroundLibFile(context, library);
if (!workaroundFile.exists()) {
unpackLibrary(context, library);
}
System.load(workaroundFile.getAbsolutePath());
}
可以看出,如果因为SO打的参差不齐导致了APK在安装的时候SO就已经有遗漏的没有被安装进lib的加载目录。那么System.loadLibrary的时候便会有异常,然后代码尝试解压并释放所需要的SO文件,但是这个时候只能通过System.load来加载了,又由于当前是arm64-v8a的机器,所以就出现了Use 32-bit jni libraries on 64-bit android - Stack Overflow的问题。
解决办法:
- APK包打的时候把SO打的齐全了,并建议只保留一个目录足够(armeabi或armeabi-v7a保留一个)。
- 云捕SDK在发现上述问题之后,尝试解压释放SO的时候,把解压目录设置到lib的加载路径顺序里去,并继续使用System.loadLibrary来加载(而不是System.load)。并在第一次System.loadLibrary出现异常时,面包屑告诉足够多的信息,例如是否是SO不存在。
- java代码混淆导致。
由于Native层需要注册到java层函数,如果java层对应的类名和函数名在打包的时候被混淆了,肯定是会出现异常的。此类问题比较定位解决,但是也比较容易忘记。解决办法就是在proguard混淆时keep掉对应的类和函数。
注册方式不对,或已经被其他类注册。
早期的崩溃捕获功能是在加壳里用的,后来把崩溃捕获的代码单独抽出为云捕SDK,为了保证复用,加壳和云捕SDK共同使用一个libbugrpt.so。外壳如果注册了,则云捕不再注册。如果外壳已经注册过了,云捕仍然要继续注册使用,就会出现上面的错误。解决办法是:当外壳已经注册启用了崩溃捕获,则云捕不再启动。empty/missing DT_HASH in "libxxxx.so" (built with --hash-style=gnu?)
java.lang.UnsatisfiedLinkError: dlopen failed: empty/missing DT_HASH in "libxxxx.so" (built with --hash-style=gnu?)
at java.lang.Runtime.loadLibrary(Runtime.java:371)
at java.lang.System.loadLibrary(System.java:989)
c++ - Android NDK UnsatisfiedLinkError: "dlopen failed: empty/missing DT_HASH" - Stack Overflow
总结
如果问题出现时可以尝试通过以上的几种方法来排查,如果有其他没有罗列的情形可以发给我,我将会持续收集整理并更新,以期帮助更多的开发者解决问题。
如果想要规避以上的问题,最好的办法就是打好打全相应CPU架构的SO文件。
另外你也可以直接使用云捕SDKRelinker.loadLibrary功能,来帮助你安全加载SO以降低此类UnsatisfiedLinkError的异常。
参考
[持续更新]UnsatisfiedLinkError常见问题及解决方案的更多相关文章
- 关于ASP.NET MVC开发设计中出现的问题与解决方案汇总 【持续更新】
最近一直用ASP.NET MVC 4.0 +LINQ TO SQL来开发设计公司内部多个业务系统网站,在这其中发现了一些问题,也花了不少时间来查找相关资料或请教高人,最终都还算解决了,现在我将这些问题 ...
- HBase常见问题答疑解惑【持续更新中】
HBase常见问题答疑解惑[持续更新中] 本文对HBase开发及使用过程中遇到过的常见问题进行梳理总结,希望能解答新加入的HBaser们的一些疑惑. 1. HTable线程安全吗? HTable不是线 ...
- webpack1.x环境配置与打包基础【附带各种 "坑" 与解决方案!持续更新中...】
首先介绍传统模块化开发的主流方案: 1.基与CMD的sea.js,玉伯提出的解决方案,据说原来京东团队在使用.用时才定义,就近加载. 2.基于AMD的require.js,之前在用.提前声明与定义.国 ...
- BAT 前端开发面经 —— 吐血总结 前端相关片段整理——持续更新 前端基础精简总结 Web Storage You don't know js
BAT 前端开发面经 —— 吐血总结 目录 1. Tencent 2. 阿里 3. 百度 更好阅读,请移步这里 聊之前 最近暑期实习招聘已经开始,个人目前参加了阿里的内推及腾讯和百度的实习生招聘, ...
- 消息队列面试题、RabbitMQ面试题、Kafka面试题、RocketMQ面试题 (史上最全、持续更新、吐血推荐)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...
- java视频教程 Java自学视频整理(持续更新中...)
视频教程,马士兵java视频教程,java视频 1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播 ...
- ( 译、持续更新 ) JavaScript 上分小技巧(四)
后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址: 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第二篇地址:( 译.持续更新 ) JavaScr ...
- ( 译、持续更新 ) JavaScript 上分小技巧(三)
最近家里杂事较多,自学时间实在少的可怜,所以都在空闲时间看看老外写的内容,学习之外顺便翻译分享~等学习的时间充足些再写写自己的一些学习内容和知识点分析(最近有在接触的:复习(C#,SQL).(学习)T ...
- 系列文章:老项目的#iPhone6与iPhone6Plus适配#(持续更新中,更新日期2014年10月12日 星期日 )
本文永久地址为http://www.cnblogs.com/ChenYilong/p/4020399.html ,转载请注明出处. ********************************** ...
随机推荐
- FreeMarker模板语法
四.FreeMarker模板语法 要编写复杂的模板需要熟悉FreeMarker语法规则,官网有详细说明,中文帮助也比较详细了,下面这些内容是从网上收罗来的,感谢网友的分享,经过整理与修改的内容如下.建 ...
- wicket基础应用(1)--使用wicket对表单中的数据进行验证
作者:lhx1026 出处:http://lhx1026.iteye.com/ wicket基础应用(1)--使用wicket对表单中的数据进行验证 举个例子: 1.有一个Java文件SysCharg ...
- Leetcode 111 Minimum Depth of Binary Tree 二叉树
找出最短的从叶子到根的路径长 可以回忆Maximum Depth of Binary Tree的写法,只不过在!root,我把它改成了10000000,还有max函数改成了min函数,最后的值如果是1 ...
- c#中的事件
之前的博客讲到委托,委托本质上是将方法作为方法的参数传给方法.实际开发中,实现某个功能的的代码通常会封装成一个类,本例中字符串处理封装成MyStringProc类, 代码如下: namespace D ...
- 在ArcGIS空间数据库中增加点数据的方法
1.新建一个mxd(ArcMAP)文件 2.从ArcCatalog中把要编辑的图层拖到ArcMAP中 3.从ArcCatalog中拖一个参照图层到ArcMAP中,比如临沂市的县级区划图 4.打开Edi ...
- strcmp传入nil导致崩溃
现象:连接电脑可以正常启动程序,不连接电脑启动程序就崩溃. 崩溃信息: BSXPCMessage received error for message: Connection invalid HW k ...
- lampp 在linux ubuntu下自动开机启动
lampp 在linux ubuntu下自动开机启动 lampp在linux下是不会自动启动的.需要手工处理.如下: 假如,你的lampp安装在 /opt/lampp 目录下,那么可以如下处理: 1. ...
- Revit中如何控制图元的显示与隐藏
Revit建模过程中经常会遇到图元的相互遮挡的情况,为了将一些图元显示出来,就需要将一些不需要显示的图元隐藏掉,这就需要用到"隐藏/重置"工具,在Revit绘图窗口左下角提供了一排 ...
- LeetCode:Container With Most Water,Trapping Rain Water
Container With Most Water 题目链接 Given n non-negative integers a1, a2, ..., an, where each represents ...
- mac os 中安装memcahed
1.先安装macport sudo port selfupdate #更新当前Marport (如果port 不可以时可以考虑此操作) sudo prot -d selfupdate #替换更 ...