• Android加载SO库UnsatisfiedLinkError错误的原因及解决方案


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

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

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

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

    然后的想法是放置的 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

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

  • 相关阅读:
    搜索复习-中级水题
    搜索复习-基础水题(一共12道)
    TCPThree_C杯 Day1
    bzoj1579 道路升级
    bzoj3732 Network(NOIP2013 货车运输)
    bzoj1624 寻宝之路
    bzoj1430 小猴打架
    bzoj2763 飞行路线
    2017-10-28-afternoon-清北模拟赛
    2017-10-28-morning-清北模拟赛
  • 原文地址:https://www.cnblogs.com/daxingxing/p/5408687.html
Copyright © 2020-2023  润新知