Android本机运行时无法加载符号,即使它们实际上是在加载的.so文件中找到的

Android native runtime fails to load symbols even though they are actually found in the loaded .so files

本文关键字:加载 实际上 so 文件 运行时 本机 符号 Android      更新时间:2023-10-16

我已经使用NDK v15.2编译了ffmpeg v3.4,我正在创建一个名为ffmpeg jni的包装器库。

static {
try {
System.loadLibrary("avutil");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
System.loadLibrary("swscale");
System.loadLibrary("avfilter");
System.loadLibrary("ffmpeg-jni"); // Exception here line#101
loadedLibraries = true;
} catch (Throwable e) {
e.printStackTrace();
}
}

下面是加载包装器库时引发的异常。

10-24 11:12:13.819 21499-21499/com.myeglu.android.canary.staging W/System.err: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "av_register_all" referenced by "/data/app/com.myeglu.android.canary.staging-2/lib/arm/libffmpeg-jni.so"...

但是,令我惊讶的是,这个函数是在libavformat.so中定义的,它成功加载;从nm工具输出中可以清楚地看出,av_register_all()函数是在libavformat.so 中定义的(T)

以下是所有预先构建的库的链接,这些库在运行时很难实现和平。(除了ffmpeg库之外,还有一些其他库)

https://drive.google.com/drive/folders/0B20ExoMyOP_UeDhNdmwzc2tjR3M?usp=sharing

有人帮我了解在这种情况下我可能会错过什么。谢谢你抽出时间。

首先,您应该以正确的顺序显式列出所有需要的库,或者让系统解析依赖关系(如果您的平台至少是Lollipop)。

具体来说,libavcodec需要libswresample

但是ffmpeg jni似乎没有正确构建。其动态部分仅列出

0x00000001 (NEEDED) Shared library: [libandroid.so]
0x00000001 (NEEDED) Shared library: [libjnigraphics.so]
0x00000001 (NEEDED) Shared library: [libavcodec.so]
0x00000001 (NEEDED) Shared library: [liblog.so]
0x00000001 (NEEDED) Shared library: [libc.so]

此外,.dynsym表包含

5: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND av_register_all

相反,我希望

5: 00000000     0 FUNC    GLOBAL DEFAULT  UND av_register_all@LIBAVFORMAT_57 (4)

请注意,avcodec_find_decoder的符号类型以及来自libavcodec的其他引用。因此库中的是正确的。

您是否可以将LOCAL_ALLOW_UNDEFINED_SYMBOLS=true用于libffmpeg jni.so

更新:实际上,cmake使用Android工具链准备的CMAKE_SHARED_LINKER_FLAGS--no-undefined传递给链接器;通过覆盖这个变量,您有效地允许了未定义的符号(并丢失了一些其他为Android调整的重要标志)。底线是,重写CMAKE标准变量是危险的。