2012-06-15 16 views
13

問題:ロードは、他の共有ライブラリに依存LIBSを共有

は私がlibgstreamer-0.10.so(アンドロイド-8プラットフォーム用にコンパイルのGStreamer-のAndroid NDKバンドルLIBS) libに共有使用し、EclipseでAndroidアプリを構築しています。私は新しいフォルダlibs/armeabiをプロジェクトのルートフォルダに作成してそこに置いた。また、私はそれに付属の他のすべてのライブラリ(158個)を同じフォルダに入れました。私は私のメインのアクティビティコードでこれを置く場合:

static{ 
    System.loadLibrary("gstreamer-0.10"); 
} 

し、ビルド/アンドロイド-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) 

libglib-2.0.soは同じですフォルダをlibgstreamer-0.10.soとし、なぜロードされないのですか?私はそのリンカが/system/libからロードしようとしていて、libglib-2.0.soはそこにはありませんが、なぜそれがlibgstreamer-0.10.soである場所からロードされていないのですか?

だから私は、このコマンドを使用してに依存するのlibs libgstreamer-0.10.so発見するために行ってきました:

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に配置されている最初の4は(/data/data/com.marko.gstreamer_test/libに位置しています)をデバイス上に作成します。

論理的な解決策:

だから私はlibgstreamer-0.10.soをロードする前に、私は、これらの4つのLIBSをロードしようと、それが働いた:

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"); 
} 

を私の質問は以下のとおりです。

  1. 私は何とかアプリケーションの場所からもlibsをロードするようリンカーに指示できますか?いくつかの環境変数などにパスを追加するのと同じように... LinuxのPATHに似ています。

  2. 私のソリューションに悪い副作用がありますか?つまり、リンカは、libgstreamer-0.10.soをロードする前にこれを行うでしょう。しかし、これは何か問題を作りますか?

  3. 私のライブラリを/system/libフォルダにインストールすることはできますか?

+4

実際にAndroid開発者自身が推奨する解決策は、https://groups.google.com/forum/?fromgroups#!topic/android-ndk/F7DnfSQt8qsですバギー。 –

+0

明示的に読み込むライブラリをどのように決定しましたか? –

+0

@dpk 'arm-linux-androideabi-readelf -d libgstreamer-0.10.so'は依存関係のリストを与えます。それらのうちのいくつかはすでにロードされていますが(libcなど)、明示的にロードする必要があります。 – chrisvarnz

答えて

26

https://groups.google.com/forum/?fromgroups#!msg/android-ndk/J3lzK4X--bM/4YaijymZy_AJ

Yes, and this is the documented behaviour: you must load libraries in reverse dependency order explicitely. [...] It is a limitation of the system.

In a nutshell, the dynamic linker doesn't know anything about your application (e.g. where its libraries live), it only knows about the LD_LIBRARY_PATH value that was set when the process was created. When you start an Android application, you really fork the Zygote process, you don't create a new one, so the library search path is the initial one and doesn't include your app's /data/data//lib/ directory, where your native libraries live. This means that dlopen("libfoo.so") will not work, because only /system/lib/libfoo.so will be searched.

When you call System.loadLibrary("foo") from Java, the VM framework knows the application's directory, so it can translate "foo" into "/data/data//lib/libfoo.so", then call dlopen() with this full path, which will work.

It libfoo.so references "libbar.so", then the dynamic linker will not be able to find the latter.

Add to this that even if you update LD_LIBRARY_PATH from native code, the dynamic linker will not see the new value. For various low-level reasons, the dynamic linker contains its own copy of the program's environment as it was when the process was created (not forked). And there is simply no way to update it from native code. This is by design, and changing this would have drastic security constraints. For the record, this is also how the Linux dynamic linker works, this forces any program that needs a custom library search path to use a wrapper script to launch its executable (e.g. Firefox, Chrome and many others).

によると、私はこれが文書化されている場所を求めて、著者を電子メールで送信しました。

TorのLillqvistは、回避策を提供するために行く:https://groups.google.com/d/msg/android-ndk/J3lzK4X--bM/n2zUancIFUEJ

To be more verbose, what that lo_dlopen() function does is:

  • Searches where the shared object in question is. It searches a set of directories passed to it by the Java code. The Java code looks at LD_LIBRARY_PATH and adds the app's lib directory to that.
  • Opens the found shared object file and reads the ELF structures in it . Not all, but just enough to find out what shared objects it needs (the DT_NEEDED ones as displayed by arm-linux-androideabi-readelf -d). It calls itself recursively on the needed shared objects.
  • Only after that, i.e. after making sure that all needed other shared objects have been loaded, it calls the real dlopen() on the found full pathname to the shared object.

あなたはhttp://cgit.freedesktop.org/libreoffice/core/tree/sal/android/lo-bootstrap.c?id=5510127e89d6971a219ce3664e4631d6c6dda2b1

UPDATEで彼のコードを見つけることができます:http://code.google.com/p/android/issues/detail?id=34416によると、このコードは、2012年12月の時点でのAndroidに統合されました。わーい!依存関係は、APIレベル18以上のデバイス用に自動的に読み込まれます。それより古いAPIレベルをサポートしている場合は、依然として依存関係をリストする必要があります。

3
  1. 私はあなたのJavaアプリケーションのために何ができるかわかりません。ネイティブコマンドラインアプリケーションの場合は、アプリケーションを宣言する前にLD_LIBRARY_PATH環境変数を設定することで実行できます。

  2. これは正しい解決策です。 NDKドキュメントのどこかに、このようにすべての依存ライブラリをロードする必要があることが言及されています。

  3. いいえ、できません。

関連する問題