Android 加载依赖于其他共享库的共享库

Android 加载依赖于其他共享库的共享库,android,linker,android-ndk,gstreamer,Android,Linker,Android Ndk,Gstreamer,问题: 我正在Eclipse中构建Android应用程序,它使用共享liblibgstreamer-0.10。我在项目根文件夹中创建了一个新文件夹libs/armeabi,并将其放在那里。此外,我还将它附带的所有其他lib(158个)放在同一个文件夹中。如果我把它放在我的主要活动代码中: static{ System.loadLibrary("gstreamer-0.10"); } 并在Android-8 emulator上构建/安装/运行我的应用程序,它会抛出以下错误: 06-15

问题:

我正在Eclipse中构建Android应用程序,它使用共享lib
libgstreamer-0.10。我在项目根文件夹中创建了一个新文件夹
libs/armeabi
,并将其放在那里。此外,我还将它附带的所有其他lib(158个)放在同一个文件夹中。如果我把它放在我的主要活动代码中:

static{
    System.loadLibrary("gstreamer-0.10");
}
并在Android-8 emulator上构建/安装/运行我的应用程序,它会抛出以下错误:

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)
现在,
libglib-2.0.so
libgstreamer-0.10.so
位于同一文件夹中,为什么不加载它?我发现链接器试图从
/system/lib
libglib-2.0加载它。所以
不存在,但为什么它不从
libgstreamer-0.10所在的位置加载它呢

因此,我去发现libs
libgstreamer-0.10。因此,使用此命令取决于:

arm-linux-androideabi-readelf -d libgstreamer-0.10.so
结果:

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
前四个
libglib-2.0.so、libgobject-2.0.so、libgthread-2.0.so、libgmodule-2.0.so
都位于同一文件夹
libgstreamer-0.10。so
位于设备上的(
/data/com.marko.gstreamer\u test/lib
)中

逻辑解决方案:

因此,在加载
libgstreamer-0.10之前,我尝试加载这四个lib。因此,它起到了作用:

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");
}
我的问题是:

  • 我可以告诉链接器也从应用程序位置加载libs吗?例如,将路径添加到某个环境变量或其他内容。。。类似于Linux上的路径

  • 我的解决方案是否有一些不良副作用?我的意思是,链接器在加载libgstreamer-0.10.so之前也会这样做。但这会带来任何问题吗

  • 我可以将我的libs安装到无根设备上的/system/lib文件夹吗

  • 我不确定你能为Java应用做些什么。对于本机命令行应用程序,可以通过在声明应用程序之前设置LD_LIBRARY_PATH环境变量来实现

  • 这是正确的解决方案。NDK文档中的某个地方提到,您需要以这种方式加载所有依赖库

  • 不,你不能那样做

  • 是的,这就是记录在案的行为:您必须以相反的依赖顺序明确地加载库。[…]这是该系统的一个限制

    简而言之,动态链接器不知道有关应用程序的任何信息(例如,其库所在的位置),它只知道在创建进程时设置的LD_LIBRARY_PATH值。当你启动一个Android应用程序时,你实际上是在分叉合子过程,而不是创建一个新的合子过程,所以库搜索路径是初始路径,不包括你的应用程序的/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继续提供一个解决方案:

    更详细地说,lo_dlopen()函数的作用是:

    • 搜索相关共享对象所在的位置。它搜索Java代码传递给它的一组目录。Java代码查看LD_LIBRARY_路径,并将应用程序的lib目录添加到该路径中
    • 打开找到的共享对象文件并读取其中的ELF结构。不是全部,但只足以找出它需要什么共享对象(DT_需要arm linux AndroidAbi readelf-d显示的对象)。它递归地调用所需的共享对象
    • 只有在这之后,即在确保所有需要的其他共享对象都已加载之后,它才会在找到的共享对象完整路径名上调用真正的dlopen()
    你可以在


    更新:根据该代码,自2012年12月起已集成到Android中。耶!API级别为18及以上的设备会自动加载依赖项。如果您支持的是较旧的API级别,那么您仍然需要列出依赖项。

    这种黑客行为实际上是Android开发人员自己推荐的解决方案:对于这样的技术决策,难怪Android有这么多缺陷。你是如何确定要显式加载哪些库的?@dpk
    arm-linux-androideabi-readelf-d libgstreamer-0.10。因此
    给出了依赖项列表。其中有些已经加载(libc等),但有些需要显式加载。