如何解决应用中不同版本libgnustl_shared.so的依赖冲突问题
问题描述
我在应用中集成了SDK A与SDK B,二者均依赖libgnustl_shared.so但版本不同,导致加载冲突:
- 若加载SDK A所需的版本,SDK B运行时出现符号缺失错误:
2024-01-22 16:18:45.786 17159-17159 MainActivity D initAkuvoxSDK 2024-01-22 16:18:45.804 17159-17159 Akuvox E null: initAKTalkSDK(6): initAKTalkSDK 2024-01-22 16:18:45.833 17159-17159 MainActivity D initSDK faild:dlopen failed: cannot locate symbol "vpx_codec_destroy" referenced by "/data/app/~~oEVKSXHX5pZYt2cfbKQxUA==/com.lifesmart.nature.feature.imou.app-W4ytQs2rHgy2kvJJ4im0qw==/base.apk!/lib/armeabi-v7a/libmediaengine.so"...
- 若加载SDK B所需的版本,SDK A运行时出现另一个符号缺失错误:
2024-01-22 17:23:16.047 19126-19126 System.err W java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_ZNSsD1Ev" referenced by "/data/app/~~bAS2agkoBsPcKUDA9pUdcg==/com.lifesmart.nature.feature.imou.app-Rf3ByH7-rhJyJFcP7_velw==/base.apk!/lib/armeabi-v7a/libLechangeSDK.so"... 2024-01-22 17:23:16.048 19126-19126 System.err W at java.lang.Runtime.loadLibrary0(Runtime.java:1087) 2024-01-22 17:23:16.048 19126-19126 System.err W at java.lang.Runtime.loadLibrary0(Runtime.java:1008) 2024-01-22 17:23:16.048 19126-19126 System.err W at java.lang.System.loadLibrary(System.java:1664) 2024-01-22 17:23:16.048 19126-19126 System.err W at com.lechange.opensdk.a.<clinit>(Loader.java:18) 2024-01-22 17:23:16.048 19126-19126 System.err W at com.lechange.opensdk.a.a(Loader.java:35) 2024-01-22 17:23:16.048 19126-19126 System.err W at com.lechange.opensdk.api.LCOpenSDK_Api_Impl$SingletonHolder.<clinit>(LCOpenSDK_Api_Impl.java:58) 2024-01-22 17:23:16.049 19126-19126 System.err W at com.lechange.opensdk.api.LCOpenSDK_Api_Impl$SingletonHolder.a(LCOpenSDK_Api_Impl.java:50) 2024-01-22 17:23:16.049 19126-19126 System.err W at com.lechange.opensdk.api.LCOpenSDK_Api_Impl.initOpenApi(LCOpenSDK_Api_Impl.java:94) 2024-01-22 17:23:16.049 19126-19126 System.err W at com.lechange.opensdk.api.LCOpenSDK_Api.initOpenApi(LCOpenSDK_Api.java:48) 2024-01-22 17:23:16.049 19126-19126 System.err W at com.lifesmart.nature.feature.imou.pkg.sdk.SDKWrapper.init(SDKWrapper.kt:27) 2024-01-22 17:23:16.049 19126-19126 System.err W at com.lifesmart.nature.feature.imou.app.LeCameraDialogFragment$initData$1.invoke(LeCameraDialogFragment.kt:116) 2024-01-22 17:23:16.049 19126-19126 System.err W at com.lifesmart.nature.feature.imou.app.LeCameraDialogFragment$initData$1.invoke(LeCameraDialogFragment.kt:114) 2024-01-22 17:23:16.050 19126-19126 System.err W at com.lifesmart.nature.feature.imou.app.LeCameraDialogFragment.initData$lambda$2(LeCameraDialogFragment.kt:114) 2024-01-22 17:23:16.050 19126-19126 System.err W at com.lifesmart.nature.feature.imou.app.LeCameraDialogFragment.$r8$lambda$nctCiCHEf4Q0fUDv8wF2ZEwZznY(Unknown Source:0) 2024-01-22 17:23:16.050 19126-19126 System.err W at com.lifesmart.nature.feature.imou.app.LeCameraDialogFragment$$ExternalSyntheticLambda0.onChanged(Unknown Source:2) 2024-01-22 17:23:16.050 19126-19126 System.err W at androidx.lifecycle.LiveData.considerNotify(LiveData.java:131) 2024-01-22 17:23:16.050 19126-19126 System.err W at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:149) 2024-01-22 17:23:16.050 19126-19126 System.err W at androidx.lifecycle.LiveData.setValue(LiveData.java:307) 2024-01-22 17:23:16.051 19126-19126 System.err W at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50) 2024-01-22 17:23:16.051 19126-19126 System.err W at androidx.lifecycle.LiveData$1.run(LiveData.java:91) 2024-01-22 17:23:16.051 19126-19126 System.err W at android.os.Handler.handleCallback(Handler.java:938) 2024-01-22 17:23:16.051 19126-19126 System.err W at android.os.Handler.dispatchMessage(Handler.java:99) 2024-01-22 17:23:16.052 19126-19126 System.err W at android.os.Looper.loop(Looper.java:223) 2024-01-22 17:23:16.052 19126-19126 System.err W at android.app.ActivityThread.main(ActivityThread.java:7660) 2024-01-22 17:23:16.052 19126-19126 System.err W at java.lang.reflect.Method.invoke(Native Method) 2024-01-22 17:23:16.052 19126-19126 System.err W at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 2024-01-22 17:23:16.052 19126-19126 System.err W at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
应用配置:
- minSdk 21
- targetSdk 29
- compileSdk 33
通过nm -D命令验证,两个版本的so符号互补:
nm -D /Users/hanwen/temp/so_conflict/libgnustl_shared_SDK_A.so | grep _ZNSsD1Ev 0008adac W _ZNSsD1Ev nm -D /Users/hanwen/temp/so_conflict/libgnustl_shared_SDK_A.so | grep vpx_codec_destroy # no output nm -D /Users/hanwen/temp/so_conflict/libgnustl_shared_SDK_B.so | grep _ZNSsD1Ev # no output nm -D /Users/hanwen/temp/so_conflict/libgnustl_shared_SDK_B.so | grep vpx_codec_destroy 0005e92c T vpx_codec_destroy
目前已采用多进程方案隔离两个SDK,但内存占用较高,寻求其他可行解决方案。
替代解决方案
1. 合并两个版本的libgnustl_shared.so
由于两个so的符号互补(无同名冲突符号),可以将两者合并为一个包含所有必要符号的so:
- 使用
objcopy工具分别提取两个so的代码段、数据段 - 将提取的段合并到一个新的libgnustl_shared.so中,处理重定位信息
- 替换应用中原有的两个版本so,确保两个SDK都能找到所需符号
2. 静态链接libgnustl到SDK
- 联系SDK提供商,要求提供静态链接
libgnustl_static.a的版本,避免动态依赖冲突 - 若无法获取源码,可尝试使用
patchelf修改SDK的so,将动态依赖改为静态嵌入(需逆向工程基础,难度较高)
3. Android命名空间隔离(API 24+)
从Android 7.0(API 24)开始支持动态库命名空间,可分别为两个SDK创建独立的命名空间:
- 加载SDK前,用
dlopen打开对应版本的libgnustl_shared.so,指定RTLD_LOCAL和RTLD_NOW - 调用
android_create_namespace创建独立命名空间,关联该so - 加载SDK的so时,指定使用对应命名空间,确保符号查找隔离
- 针对minSdk 21的兼容:API >=24时使用该方案,API <24时 fallback到多进程
4. 符号补全
针对缺失的符号编写补全代码,编译成独立so提前加载:
- 提取缺失符号的实现(比如从SDK B的libgnustl中提取
vpx_codec_destroy),或编写兼容实现 - 将补全代码编译成so,在加载SDK前先加载该so,让动态链接器找到缺失符号
- 此方案适合符号缺失较少的场景,当前情况中补全一个符号即可解决冲突
内容的提问来源于stack exchange,提问作者Albert Culajay
相关产品推荐
相关产品推荐

