Cip*_*ipi 14 linker android gstreamer android-ndk
问题:
我正在Eclipse中构建Android应用程序,它使用共享库libgstreamer-0.10.so (为Android-8平台编译的GStreamer-android NDK Bundle库).我libs/armeabi在项目根文件夹中创建了新文件夹并将其放在那里.此外,我已将所有其他随附的库(其中158个)放在同一个文件夹中.如果我把它放在我的主要活动代码中:
static{
System.loadLibrary("gstreamer-0.10");
}
Run Code Online (Sandbox Code Playgroud)
在Android-8模拟器上构建/安装/运行我的应用程序,它会抛出此错误:
06-15 21:54:00.835: E/AndroidRuntime(402): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1962]: 33 could not load needed library 'libglib-2.0.so' for 'libgstreamer-0.10.so' (load_library[1104]: Library 'libglib-2.0.so' not found)
Run Code Online (Sandbox Code Playgroud)
现在,和libglib-2.0.so它在同一个文件夹中libgstreamer-0.10.so,为什么没有加载?我得到链接器试图加载它/system/lib,libglib-2.0.so只是不存在,但为什么不从它的位置加载它libgstreamer-0.10.so?
所以我libgstreamer-0.10.so用这个命令去发现哪些lib 依赖:
arm-linux-androideabi-readelf -d libgstreamer-0.10.so
Run Code Online (Sandbox Code Playgroud)
结果:
Dynamic section at offset 0x118b64 contains 29 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libglib-2.0.so]
0x00000001 (NEEDED) Shared library: [libgobject-2.0.so]
0x00000001 (NEEDED) Shared library: [libgthread-2.0.so]
0x00000001 (NEEDED) Shared library: [libgmodule-2.0.so]
0x00000001 (NEEDED) Shared library: [libdl.so]
0x00000001 (NEEDED) Shared library: [libm.so]
0x00000001 (NEEDED) Shared library: [libstdc++.so]
0x00000001 (NEEDED) Shared library: [libc.so]
0x0000000e (SONAME) Library soname: [libgstreamer-0.10.so]
0x00000010 (SYMBOLIC) 0x0
Run Code Online (Sandbox Code Playgroud)
前四个libglib-2.0.so, libgobject-2.0.so, libgthread-2.0.so, libgmodule-2.0.so都位于同一文件夹libgstreamer-0.10.so中,位于/data/data/com.marko.gstreamer_test/lib设备上的()中.
逻辑解决方案:
所以,我在加载之前尝试加载这四个库libgstreamer-0.10.so,它工作正常:
static{
System.loadLibrary("glib-2.0");
System.loadLibrary("gthread-2.0");
System.loadLibrary("gobject-2.0");
System.loadLibrary("gmodule-2.0");
System.loadLibrary("gstreamer-0.10");
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
我可以以某种方式告诉链接器也从应用程序位置加载库吗?就像添加一些环境变量的路径一样......类似于Linux上的PATH.
我的解决方案是否有一些不良副作用?我的意思是,链接器在加载libgstreamer-0.10.so之前也会这样做.但这会有什么问题吗?
我可以在无根设备上将我的lib安装到/ system/lib文件夹吗?
Gil*_*ili 26
根据https://groups.google.com/forum/?fromgroups#!msg/android-ndk/J3lzK4X--bM/4YaijymZy_AJ
是的,这是记录的行为:您必须明确地以反向依赖顺序加载库.[...]这是系统的限制.
简而言之,动态链接器对您的应用程序一无所知(例如,其库存在的位置),它只知道创建进程时设置的LD_LIBRARY_PATH值.当你启动一个Android应用程序时,你真的分叉了Zygote进程,你没有创建一个新的,所以库搜索路径是初始的,不包括你的应用程序的/ data/data // lib /目录,其中你的本地图书馆.这意味着dlopen("libfoo.so")将无法工作,因为只会搜索/system/lib/libfoo.so.
当您从Java调用System.loadLibrary("foo")时,VM框架知道应用程序的目录,因此它可以将"foo"转换为"/data/data//lib/libfoo.so",然后调用dlopen()这条完整的道路,将起作用.
它libfoo.so引用"libbar.so",然后动态链接器将无法找到后者.
除此之外,即使您从本机代码更新LD_LIBRARY_PATH,动态链接器也不会看到新值.出于各种低级别的原因,动态链接器包含自己的程序环境副本,就像创建进程(不分叉)时一样.并且根本无法从本机代码更新它.这是设计的,改变这将有严重的安全限制.为了记录,这也是Linux动态链接器的工作方式,这迫使任何需要自定义库搜索路径的程序使用包装器脚本来启动其可执行文件(例如Firefox,Chrome和许多其他程序).
我已经通过电子邮件向作者询问了这些文件的位置.
Tor Lillqvist继续提供解决方法:https://groups.google.com/d/msg/android-ndk/J3lzK4X--bM/n2zUancIFUEJ
为了更详细,lo_dlopen()函数的作用是:
- 搜索相关共享对象的位置.它搜索Java代码传递给它的一组目录.Java代码查看LD_LIBRARY_PATH并将应用程序的lib目录添加到该目录中.
- 打开找到的共享对象文件并读取其中的ELF结构.不是全部,而是足以找出它需要的共享对象(由arm-linux-androideabi-readelf -d显示的DT_NEEDED).它以递归方式调用所需的共享对象.
- 只有在那之后,即在确保已经加载了所有需要的其他共享对象之后,它才会在找到的共享对象的完整路径名上调用真正的dlopen().
你可以在http://cgit.freedesktop.org/libreoffice/core/tree/sal/android/lo-bootstrap.c?id=5510127e89d6971a219ce3664e4631d6c6dda2b1找到他的代码.
更新:根据http://code.google.com/p/android/issues/detail?id=34416,此代码已于2012年12月集成到Android中.是的!API级别为18及以上的设备会自动加载依赖项.如果您支持较旧的API级别,则仍需要列出依赖项.
| 归档时间: |
|
| 查看次数: |
15639 次 |
| 最近记录: |