- 浏览: 2144443 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (1240)
- mac/IOS (287)
- flutter (1)
- J2EE (115)
- android基础知识 (582)
- android中级知识 (55)
- android组件(Widget)开发 (18)
- android 错误 (21)
- javascript (18)
- linux (70)
- 树莓派 (18)
- gwt/gxt (1)
- 工具(IDE)/包(jar) (18)
- web前端 (17)
- java 算法 (8)
- 其它 (5)
- chrome (7)
- 数据库 (8)
- 经济/金融 (0)
- english (2)
- HTML5 (7)
- 网络安全 (14)
- 设计欣赏/设计窗 (8)
- 汇编/C (8)
- 工具类 (4)
- 游戏 (5)
- 开发频道 (5)
- Android OpenGL (1)
- 科学 (4)
- 运维 (0)
- 好东西 (6)
- 美食 (1)
最新评论
-
liangzai_cool:
请教一下,文中,shell、C、Python三种方式控制led ...
树莓派 - MAX7219 -
jiazimo:
...
Kafka源码分析-序列5 -Producer -RecordAccumulator队列分析 -
hp321:
Windows该命令是不是需要安装什么软件才可以?我试过不行( ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
hp321:
Chenzh_758 写道其实直接用一下代码就可以解决了:JP ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
huanghonhpeng:
大哥你真强什么都会,研究研究。。。。小弟在这里学到了很多知识。 ...
android 浏览器
在2012年KeepSafe的创业初期,我们试图找到一种为Android应用加密的方案,通过多次迭代与原型设计,我们最终找到了最佳方案——利用JNI(Java本地接口)。我们决定将接口写入Java加密库中,完全通过JNI来调用加密库,以实现加密与解密。我们选用了即时解决的方案,以期将对用户体验的影响减到最小,并决定在方案通过后就部署到生产应用上。我们严格测试代码,确认一切顺利,直到事情超出了控制。
遇到可怕的“UnsatisfiedLinkError”错误
在版本发布、大家焦虑地刷新错误报告之际,我们开始注意到,有一个错误反复重现。用户遇到“UnsatisfiedLinkError”错误的意思是,要么A) 我们调用的本地库不存在;要么B) 我们调用的本地方法不存在。鉴于B) 可能性在编译与基础测试时一般都能被发现,我们立即困惑于这一事实:用户并未安装我们打包在APK内的本地库。
下面有一些我们碰到过的异常样例,从标准类型的:
到更为诡异的……
出问题的库没有明确的模式可循,似乎所有库都可能会抛出异常,并不拘于某个版本的Android OS,也不拘于特定型号的设备。此外在特定情况下,一些本地库加载正常,但并非所有库都能正常加载。我们在互联网上就这个问题疯狂地搜索,寻找答案或帮助,却一无所获。我们开始发布专门的修补程序,大多都是测试性修复补丁,并附有跟踪数据,以便让我们更好地了解故障出现时的具体环境,补丁中还包括一块代码,专门负责检查本地库是否安装在正确的位置上。
此外在特定情况下,一些本地库加载正常,但并非所有库都能正常加载。
结果发现,果然是本地库缺失所导致的。这些错误并不是系统类或文件系统所导致的偶然性奇特错误,而且用户的设备似乎也是正常的。
想法1—用户设备空间用尽
在猜测异常可能原因的时候,我们最开始想到的就是:也许用户设备的空间不足而导致本地库未能正确安装。在快速检测后,我们很快发现这个想法是错误的,用户设备空间足够安装我们打包的库。
想法2—本地库未包含在更新中
第二个看似合理的猜测:在Google Play提供给用户的版本中,我们的APK被破坏掉了。在阅读了类似的一些报告后,我们更加确信这一点:据说Google Play向所有受到影响的应用开发者发送了通知,让他们通知用户在升级后先不要运行应用,因为本地库安装错误。唯一的问题在于,这个报告出现在8月份,而我们遇到问题的时候已经是好几个月以后了,而且我们也从未收到Google Play为这类错误负责的通知。此外,这一点很难证实。
想法3—与真实用户直接联调
由于在手头的十几台各种类型的设备上都无法重现这一问题,我们决定找一个遇到这个问题的用户来联调。一位友好用户决定要帮助我们,他表示应用在最近一次更新前都能正常使用。而这里有一个问题,用户表示能正常运行的应用版本正是包含了我们加密代码与本地库的那个版本,这让我们更加困惑。我们决定直接提供给这名用户一个验证过的APK包,其中包含了所有的本地库。在他安装了APK包之后,再次运行应用,又遇到了同样的UnsatisfiedLinkError错误。这证明Google Play不是问题的根源,Android的PackageManager安装过程才是问题所在,在安装期间会发生某种错误,导致APK中的本地库无法被提取。
问题在于Android的PackageManager安装过程
得出解决方案
鉴于我们发现了问题是安装过程所导致的,我们决定将该部分的安装过程复制下来,并将本地库提取到应用代码中。幸运地是,通过以下代码就能很容易的获得应用的APK文件参考:
并用来将本地库提取到内部存储中。由于APK文件只不过是ZIP文件,写个ZIP提取代码只是小事一桩。我们很快实现了代码提取和打包,大幅降低了报错率。
日均UnsatisfiedLinkError错误的总量
尽管这是件好事,我们还是发现了一些用户时不时遇到异常抛出,在此我们寻求了Google的帮助。幸运地是,他们给了我们建议:用户可以通过除了Play Store以外的其他渠道来安装我们的应用,并告诉我们了一个技巧:通过
就可以得知是哪个package安装了我们的应用。
为了减少APK大小,并确保应用尽可能在所有设备上可用,我们有支持x86、Armv7和Arm架构的应用包。每种只包含相应架构的本地库,所以很有可能某个用户安装的APK包并非是支持相应设备架构的那种。
我们开始在崩溃中记录安装包的名称,并且很快发现,问题产生的确是因为用户从各种途径安装应用,新增的UnsatisfiedLinkError错误都是由于用户手动安装应用时,选择了不适用他们设备架构的应用所致。这是最终的“问题揭秘”,我们都放下心来,这个解释简单明了。
引入ReLinker
我们决定将提取的代码打包成一个人人适用的小型库。鉴于我们所经历过的这个debug过程,不应当再有人重蹈覆辙,尤其是其中还涉及到了超出应用开发者控制能力之外的Android基础功能。
使用ReLinker十分简单,就像用
来代替标准的
在Github库中 你能找到更多ReLinker的相关内容。
问题解决
在发布修复补丁的时候,有约10万的独立用户持续不断地遇到这种崩溃性错误。我们希望ReLinker有用,不再让大家遇到UnsatisfiedLinkerError错误。
感谢
感谢谷歌的支持团队为我们指出正确的方向,还有他们在这个问题上对我们持续不断地支持!
我们的代码主要是基于Chromium类似的权宜方案。在Chromium的源代码中有一条注释,解释了Android package manager中的具体问题:
遇到可怕的“UnsatisfiedLinkError”错误
在版本发布、大家焦虑地刷新错误报告之际,我们开始注意到,有一个错误反复重现。用户遇到“UnsatisfiedLinkError”错误的意思是,要么A) 我们调用的本地库不存在;要么B) 我们调用的本地方法不存在。鉴于B) 可能性在编译与基础测试时一般都能被发现,我们立即困惑于这一事实:用户并未安装我们打包在APK内的本地库。
下面有一些我们碰到过的异常样例,从标准类型的:
java.lang.UnsatisfiedLinkError: Couldn’t load stlport_shared from loader dalvik.system.PathClassLoader[dexPath=/data/app/com.kii.safe-1.apk,libraryPath=/data/app-lib/com.kii.safe-1]: findLibrary returned null at java.lang.Runtime.loadLibrary(Runtime.java:365) at java.lang.System.loadLibrary(System.java:535) at com.kii.safe.Native.<clinit>(Native.java:16) … 63 more Caused by: java.lang.UnsatisfiedLinkError: Library stlport_shared not found at java.lang.Runtime.loadLibrary(Runtime.java:461) at java.lang.System.loadLibrary(System.java:557) at com.kii.safe.Native.<clinit>(Native.java:16) … 5 more Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: get_lib_extents[760]: 1305 — /mnt/asec/com.kii.safe-1/lib/libstlport_shared.so is not a valid ELF object at java.lang.Runtime.loadLibrary(Runtime.java:434) at java.lang.System.loadLibrary(System.java:554) at com.kii.safe.Native.<clinit>(Native.java:15) Caused by: java.lang.UnsatisfiedLinkError: Library cryptopp not found at java.lang.Runtime.loadLibrary(Runtime.java:461) at java.lang.System.loadLibrary(System.java:557) at com.kii.safe.Native.<clinit>(Native.java:17)
到更为诡异的……
Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1286]: 1748 cannot locate ‘쯰ҷЦf1Ϙ˗˞ք0Ⱉض夘Ϛ.͏闑㥁ج뭫ර⓻в^ӎ3c`+W#Ҽ?-Bַˌ֕꼠’… at java.lang.Runtime.loadLibrary(Runtime.java:370) at java.lang.System.loadLibrary(System.java:535) at com.kii.safe.Native.<clinit>(Native.java:17) Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1312]: 1327 cannot locate ‘Pܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭXߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭXߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ#ʭX Ϛߐܝ# at java.lang.Runtime.loadLibrary(Runtime.java:434) at java.lang.System.loadLibrary(System.java:554) at com.kii.safe.Native.<clinit>(Native.java:17)
出问题的库没有明确的模式可循,似乎所有库都可能会抛出异常,并不拘于某个版本的Android OS,也不拘于特定型号的设备。此外在特定情况下,一些本地库加载正常,但并非所有库都能正常加载。我们在互联网上就这个问题疯狂地搜索,寻找答案或帮助,却一无所获。我们开始发布专门的修补程序,大多都是测试性修复补丁,并附有跟踪数据,以便让我们更好地了解故障出现时的具体环境,补丁中还包括一块代码,专门负责检查本地库是否安装在正确的位置上。
此外在特定情况下,一些本地库加载正常,但并非所有库都能正常加载。
结果发现,果然是本地库缺失所导致的。这些错误并不是系统类或文件系统所导致的偶然性奇特错误,而且用户的设备似乎也是正常的。
想法1—用户设备空间用尽
在猜测异常可能原因的时候,我们最开始想到的就是:也许用户设备的空间不足而导致本地库未能正确安装。在快速检测后,我们很快发现这个想法是错误的,用户设备空间足够安装我们打包的库。
想法2—本地库未包含在更新中
第二个看似合理的猜测:在Google Play提供给用户的版本中,我们的APK被破坏掉了。在阅读了类似的一些报告后,我们更加确信这一点:据说Google Play向所有受到影响的应用开发者发送了通知,让他们通知用户在升级后先不要运行应用,因为本地库安装错误。唯一的问题在于,这个报告出现在8月份,而我们遇到问题的时候已经是好几个月以后了,而且我们也从未收到Google Play为这类错误负责的通知。此外,这一点很难证实。
想法3—与真实用户直接联调
由于在手头的十几台各种类型的设备上都无法重现这一问题,我们决定找一个遇到这个问题的用户来联调。一位友好用户决定要帮助我们,他表示应用在最近一次更新前都能正常使用。而这里有一个问题,用户表示能正常运行的应用版本正是包含了我们加密代码与本地库的那个版本,这让我们更加困惑。我们决定直接提供给这名用户一个验证过的APK包,其中包含了所有的本地库。在他安装了APK包之后,再次运行应用,又遇到了同样的UnsatisfiedLinkError错误。这证明Google Play不是问题的根源,Android的PackageManager安装过程才是问题所在,在安装期间会发生某种错误,导致APK中的本地库无法被提取。
问题在于Android的PackageManager安装过程
得出解决方案
鉴于我们发现了问题是安装过程所导致的,我们决定将该部分的安装过程复制下来,并将本地库提取到应用代码中。幸运地是,通过以下代码就能很容易的获得应用的APK文件参考:
Context.getApplicationInfo().sourceDir;
并用来将本地库提取到内部存储中。由于APK文件只不过是ZIP文件,写个ZIP提取代码只是小事一桩。我们很快实现了代码提取和打包,大幅降低了报错率。
日均UnsatisfiedLinkError错误的总量
尽管这是件好事,我们还是发现了一些用户时不时遇到异常抛出,在此我们寻求了Google的帮助。幸运地是,他们给了我们建议:用户可以通过除了Play Store以外的其他渠道来安装我们的应用,并告诉我们了一个技巧:通过
Context.getPackageManager().getInstallerPackageName(packageName);
就可以得知是哪个package安装了我们的应用。
为了减少APK大小,并确保应用尽可能在所有设备上可用,我们有支持x86、Armv7和Arm架构的应用包。每种只包含相应架构的本地库,所以很有可能某个用户安装的APK包并非是支持相应设备架构的那种。
我们开始在崩溃中记录安装包的名称,并且很快发现,问题产生的确是因为用户从各种途径安装应用,新增的UnsatisfiedLinkError错误都是由于用户手动安装应用时,选择了不适用他们设备架构的应用所致。这是最终的“问题揭秘”,我们都放下心来,这个解释简单明了。
引入ReLinker
我们决定将提取的代码打包成一个人人适用的小型库。鉴于我们所经历过的这个debug过程,不应当再有人重蹈覆辙,尤其是其中还涉及到了超出应用开发者控制能力之外的Android基础功能。
使用ReLinker十分简单,就像用
ReLinker.loadLibrary(context, “mylibrary”)
来代替标准的
System.loadLibrary(“mylibrary”);
在Github库中 你能找到更多ReLinker的相关内容。
问题解决
在发布修复补丁的时候,有约10万的独立用户持续不断地遇到这种崩溃性错误。我们希望ReLinker有用,不再让大家遇到UnsatisfiedLinkerError错误。
感谢
感谢谷歌的支持团队为我们指出正确的方向,还有他们在这个问题上对我们持续不断地支持!
我们的代码主要是基于Chromium类似的权宜方案。在Chromium的源代码中有一条注释,解释了Android package manager中的具体问题:
/** * Try to load a native library using a workaround of * http://b/13216167. * * Workaround for b/13216167 was adapted from code in * https://googleplex-android-review.git.corp.google.com/#/c/433061 * * More details about http://b/13216167: * 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. + * We make the following changes to alleviate the issue: * 1) name the native library with apk version code, e.g., * libchrome.1750.136.so, 1750.136 is Chrome version number; * 2) first try to load the library using System.loadLibrary, * if that failed due to the library file was not found, * search the named library in a /data/data/com.android.chrome/app_lib * directory. Because of change 1), each version has a different native * library name, so avoid mistakenly using the old native library. * * If named library is not in /data/data/com.android.chrome/app_lib directory, * extract native libraries from apk and cache in the directory. * * This function doesn’t throw UnsatisfiedLinkError, the caller needs to * check the return value. */
发表评论
-
jni未释放资源问题。Failed adding to JNI local ref table (has 512 entries)
2016-02-01 14:51 946Native Code 本身的内存泄漏 JNI 编程首先是一 ... -
android ApkPlug使用
2015-12-09 15:14 650直接下载附件吧, 有两个是官方的demo包,还有一个是他们技术 ... -
dynamic-load-apk-Apk动态加载框架使用初体验
2015-12-03 10:40 752因为想要将本网站上的开源代码直接做成一个能显示效果的app,决 ... -
Android动态加载进阶 代理Activity模式
2015-11-30 17:20 840技术背景 简单模式中 ... -
Android NDK rb5 文档之本地活动和应用程序
2015-11-24 22:34 763Native Activities and Applicati ... -
Android NDK rb5 文档之 native_activity.h 文件翻译
2015-11-24 22:30 953/** * Copyright (C) 2010 The A ... -
Android新技术学习——阿里巴巴免Root无侵入AOP框架Dexposed
2015-11-21 13:49 1740引用阿里巴巴无线事业部最近开源的Android平台下的无侵入运 ... -
Android NDK开发之JNI基础知识
2015-11-21 13:05 1087JAVA层与JNI层数据类型的对应 下面是一个测试方法 pu ... -
ANDROID2.2 JNI 配置luajit2
2015-11-21 11:18 693去http://luajit.org/官网下载最新的版本 在 ... -
JNI: 能否用 GetFieldID()/GetStaticFieldID()取得enum变量的属性?
2015-11-06 11:52 1772没有问题的,jni下面一样可以动态获取的 仅供参考! VOI ... -
ndk-stack定位不出崩溃代码行的问题
2015-10-30 08:51 1211NDK开发包中自带的NDK-STACK工具是可以查看崩溃栈信息 ... -
Android.mk文件详解
2015-10-27 09:23 1738Android.mk是Android提供的 ... -
NDK在增加断点时跳不进去,不管用的解决办法
2015-10-26 10:09 1049先看下面的错,如果报的不是这个那就不是我这个问题,那就不用再看 ... -
插件化的基石 -- apk动态加载
2015-09-25 09:13 921Android动态加载技术在蘑菇街的第一次实践,还是在14年的 ... -
warning:deprecated conversion from string constant to 'char *' 解决方案
2015-09-25 09:01 1772char* createClass(){ ret ... -
jni内存释放
2015-09-24 12:03 3623调用GetStringUTFChars,GetDoubleAr ... -
如何不要让ndk-build自动删除.so
2015-08-04 15:33 1059在用ndk-build的时候突然发现在编译完成之后会自动删除a ... -
超简单的NDK单步调试方法
2015-08-03 21:19 566最近为了性能需求,开始搞JNI,白手起搞真心不容易。中间差点崩 ... -
JNI调用java中的类方法和静态方法
2015-08-03 16:46 2724在JNI调用中,肯定会涉及到本地方法操作Java类中数据和方法 ... -
[转]Android JNI层实现文件的read、write与seek操作
2015-08-03 14:41 12141、 在Andr ...
相关推荐
android webView加载html 并引用本地资源(图片、字体库)
Android webview 加载网页以及本地资源以及SD资源demo,以及加载缓存资源
android studio加载本地的html的文件
与其他图片加载库相同,Glide除了可以加载网络图片之外,也可以加载本地图片。甚至还可以从各种各样奇葩的数据源中加载图片。 加载网络图片 很多情况下,我们使用图片加载库就是为了加载网络图片。网络操作是一个很...
Android的关于高德地图加载谷歌瓦片,并缓存本地的功能. 以及加载多个Marker的title都显示在地图的Demo. Android studio 3.0
android 网络和本地图片加载 支持异步加载并缓存
通过缓存加载本地图片,
android Listview分批加载+自动加载 非常不错的demo
腾讯TBS浏览服务打开本地文档(word.pdf.ppt)踩过的坑
android项目中如何加载已有so库 一起学习android 开发
Android中实现上拉加载更多的一个小Demo
demo中介绍使用webview加载本地页面,并在java代码中提供js调用事件,在html中动态生成组件button
Android播放视频,包含系统自带VideoView控件,和自定义VideoView控件,可全屏播放,案例包含了本地视频和网络视频。
android Webview加载本地图片,自适应布局大小
Android WebView 加载 PDF 文件实现。其原理就是在 app 本地搭建一个 website ,然后利用 WebView 加载这个站点,站点去实现加载显示 PDF 的目的,站点其原理也是采用 js 框架去实现的。
Android NDK开发动态加载so,采用System.load方法实现
Android 本地预览Excel,Word,PPT,PDF 解决Android asposed转Excel乱码问题 带有Jar包
Android平台的图像控件,可以异步加载网络图片、项目资源和本地图片,并且支持双指缩放、图片的基本处理 Android平台的图像控件,可以异步加载网络图片、项目资源和本地图片,并且支持双指缩放、图片的基本处理 ...
android fragment动态加载
这是一个Android异步图片加载的例子