写点什么

Android 开发中遇到加载有相同函数的 so 库时的问题

用户头像
轻口味
关注
发布于: 刚刚

1. 常见解决方案

  1. Linux 在多个库存在同名风险的时候,例如多个库引用不同版本的开源代码,实现还不同,这时候会造成调用的冲突;

  2. 通过在头文件的函数接口前加上 “ attribute((visibility("default"))) ”开放该 so 包可见的函数接口;

  3. 在 Makefile 文件中通过“CXX=g++ -fvisibility=hidden”使得未开放的函数名都保护起来。


2. 解决过程


在项目中遇到了加载 so 库比较诡异的一个现象,现记录下来,以做总结。以下以举例的方式讲述:项目中有两个 so 库,一个是 libdemojni.so,一个是 libdemojni2.so,这两个库的都有相同函数,一个是动态注册的,一个是静态注册的,在程序启动时报错:“Failed to register native method com.example.fun.HelloJni.getSecond()Ljava/lang/String;” “java.lang.UnsatisfiedLinkError: JNI_ERR returned from JNI_OnLoad in "/data/app/com.zxl.test-1/lib/arm64/libhellojni.so"。但是,我们看 maps 表(cat /proc/进程名/maps |grep hellojni)如下:


7f76231000-7f76232000 r-xp 00000000 b3:1e 1708893                        /data/app/com.zxl.test-1/lib/arm64/libhellojni2.so7f76241000-7f76242000 r--p 00000000 b3:1e 1708893                        /data/app/com.zxl.test-1/lib/arm64/libhellojni2.so7f76242000-7f76243000 rw-p 00001000 b3:1e 1708893                        /data/app/com.zxl.test-1/lib/arm64/libhellojni2.so7f76243000-7f76244000 r-xp 00000000 b3:1e 1708894                        /data/app/com.zxl.test-1/lib/arm64/libhellojni.so7f76253000-7f76254000 r--p 00000000 b3:1e 1708894                        /data/app/com.zxl.test-1/lib/arm64/libhellojni.so7f76254000-7f76255000 rw-p 00001000 b3:1e 1708894                        /data/app/com.zxl.test-1/lib/arm64/libhellojni.so
复制代码


​ 发现虽然 libhellojni.so 加载出错了,但是还是被加载到内存中了。​ 执行前面的方法 testLib(),日志如下:


V/testLib1: HelloJniV/testLib1: first2
复制代码


​ 发现第一个方法 getString()调用到的是 libhellojni.so 库,而第二个方法 getFirst()调用到的竟然是 libhellojni2.so 中的方法。


出现此种情况的原因,应该是动态注册 和 静态注册 的缘故。当加载 libdemojni.so 时,动态注册了 getString()方法,而由于动态注册 getSecond()方法时,HelloJni.java 中没有声明此方法导致动态注册中断,而我们又在 java 代码中 catch 了这个异常,因此会继续加载 libhellojni2.so。在调用方法时,我们调用 getString()方法,由于这个方法动态注册成功了,因此会调用到 libhellojni.so 中,而再调用 getFirst()方法,这个方法动态注册失败了,因此系统不会去 libhellojni.so 中查找了,转而内存中加载的其他的 so 库中查找看有没有能够匹配 getFirst()方法的函数,结果在 libhellojni2.so 中查找到了,因此调用到 libhellojni2.so 库中。


3. 总结

出现这个现象的原因在于不了解机制和疏忽大意:

  1. 只在 cpp 中增加了对应的函数,并且增加的函数注册方法也不是放在 nativeMethods[]声明的最后,而是放到了中间。

  2. 忘记在 HelloJni.java 中增加对应的方法。

这种问题都是因为粗心引起,要小心严谨。

用户头像

轻口味

关注

🏆2021年InfoQ写作平台-签约作者 🏆 2017.10.17 加入

Android音视频、AI相关领域从业者,开源RTMP播放器:https://github.com/qingkouwei/oarplayer

评论

发布
暂无评论
Android开发中遇到加载有相同函数的so库时的问题